iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 18
1

今天將焦點放在針對 Class(類別) 設計的新關鍵字。這些關鍵字在「寫出意義明確的程式碼」以及「避免低級錯誤」扮演關鍵要角。

首先,來看看 final。若用於類別的宣告上,明白指出「我這個類別不許別人再給我繼承下去我就是要絕子絕孫」,其寫法如下:

struct Base {
  virtual ~Base();
};

struct Lonely final : public Base {
   ~Lonely();
};

struct Love : public Lonely { // Error, class Lonely is final
   virtual ~Love();
};

上述 Lonely 類別的設計者將其宣告為 final,不讓人繼承自她。有很多理由這麼做,其中一個較為常見的是,Lonely 的內部實作沒有考慮到被繼承後的行為,為了避免繼承後產生「副作用」,乾脆直接宣告不給繼承。

那麼,若要基於 Lonely 的功能來擴充新的功能,該怎麼做?小明真聰明,懂得問這個好問題。要達到這個目的,可以改用組合(Composition),也就是讓新的類別把 Lonely 當做成員變數,呼叫其提供的服務來實作擴充功能。

final 也可用於成員函數,寫法如下:

struct Base {
  virtual void Shit();
  virtual void NoShit();
};

struct Lonely : public Base {
   void Shit() final;
   void NoShit();
};

struct Love : public Lonely
   void Shit(); // Error because Shit() is final
   void NoShit();
};

下一個關鍵字是 override,同樣用於類別繼承。這是個可以降低低級錯誤發生率的發明,很貼心。

struct Base {
  virtual void Shit();
};

struct Lonely : public Base {
   virtual void Shut() override; // Error, incorrect function name.
};

手腦不一致,人常有錯字。上例中,Lonely 很明顯是要實作 Shit 這個函數,但手殘打錯字。以往這類錯誤不容易發現,提高了除錯成本。加上 override 後,編譯直接報錯。

上例中的不是大便很容易看被穿,實務上,有很多讓人摸不著頭緒的錯誤,就是會讓你遇到。

接下來是幾個相似功能的關鍵字,以下列表示:

struct Lonely {
  Lonely() = default;
  ~Lonely() = default;
  
  Lonely(const Lonely& rhs) = delete;
  Lonely& oeprator=(const Lonely& rhs) = delete;
};

C++11 以前的編譯器本來就會在某些情況下幫你生成「建構式」以及「解構式」的實作碼,但規則總讓不熟悉 C++ 的人處處感受驚喜。有了 default,明著要編譯幫忙實作,要是自己雞婆也寫一個,那就報錯。

delete 則是明著說,這幾個特殊函式(Copy Ctor, Assignment Operator)不給呼叫,語義上就是「這個類別不能被複製」。以往要達到這個目的,會把那些不給用的特殊函式放到 private 段。

Modern C++ 講求程式碼的可讀性,透過這些新的關鍵字,該禁止的明白禁止,要編譯器幫忙的就明白要求,藉此寫出「不容易被誤用的類別」,這就是現代化 C++。


上一篇
DAY 16:Structured Bindings
下一篇
DAY 18: 新語法 if and switch with Initialization
系列文
山姆大叔談 C++:從歷史談起,再給個定義—Modern C++ 解惑26
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言