ps. 經 Scott 提醒發覺內容有誤, 已更新內文。
Effective C++ item 7 提到, 若想使用 abstract class A, 建議這麼做:
// a.h class A { public: virtual ~A() = 0; // 注意只有宣告沒有實作, 是 pure virtual };
但是還是得另外提供 ~A() 的實作:
// a.cpp #include "a.h" A::~A() {}
不然連結時會出錯
以 class B 繼承 A 為例, 假設程式如下:
// b.h #include "a.h" class B : public A { }; // b.cpp #include "b.h" // Nothing.
先來看少了 a.cpp 的情況。由於編譯時只會看 header, 編譯器會阻止任何嘗試生成 A 的程式, 這是我們想要的好結果, 利用宣告含有至少一個 pure virtual 函式的作法, 得到 abstract class 的性質。用 destructor 是不錯的選擇, 不會因此增加不必要的 virtual method, 況且 「base class + 使用多型」的情況要有 virtual destructor, 和使用 abstract class 的目的相合。
然後, 來看編譯 b.cpp 得到的 b.o。不論是否有呼叫到 B() 或 ~B(), 編譯器都會產生 B() 和 ~B() 的 binary code。編譯器對照 a.h 和 b.h 覺得 access level 沒有問題, 不會有編譯錯誤, 其中 ~B() 會呼叫 ~A(), ~A() 的 symbol 還未定義, 等待連結時補上。
但是, 若少了在 a.cpp 內 ~A() 的實作的話, 連結時會發覺找不到 ~A() 的 symbol, 於是有 link error。就語法來說這結果挺怪異的, 宣告為 pure virtual 卻又得提供實作才行。反之, 從實作面來看 compiler 和 linker 怎麼運作, 就不會覺得奇怪。又一次讓我覺得要理解 C++ 的語法, 得從運作的方式來理解才行。只看語法的話, 不太容易理解和記憶。
沒有留言:
張貼留言