Effective C++學習筆記總鏈接
改善程序與設計的55個具體做法學習筆記-每日1條
條款09:絕不在構造和析構過程中調用virtual函數
【技巧】
在構造和析構期間不要調用virtual函數,因爲這類調用從不下降至derived class(比起當前執行構造函數和析構函數的那層)
class Transaction // 所有交易的base class
{
public:
Transaction();
virtual void logTransaction() const = 0; // 做一份因類型不同而不同的日誌記錄(log entry)
};
Transaction::Transaction()
{
logTransaction();
}
class BuylogTransaction: public logTransaction // derived class
{
virtual void logTransaction() const;
};
...
BuylogTransaction b; // 執行會發生什麼事?
無疑會有個BuylogTransaction 構造函數被調用,但首先Transaction構造函數一定會被調用。
Transaction構造函數會執行virtual函數 logTransaction,但調用的是Transaction::logTransaction(),而不是BuylogTransaction ::logTransaction()。
base class構造期間virtual函數絕不會下降到derived class階層
或者說是,在base class 構造期間,virtual函數不是virtual 函數。
【原因】:由於base class構造函數執行更早於derived class構造函數,當base class構造函數執行時derived class的成員變量尚未初始化。
【根本原因】:在derived class對象的base class 構造期間,對象的類型是base class 而不是derived class。virtual虛函數(或者運行期類型信息(dynamic_cast 條款27和typeid))會被編譯器解析至base class類型。
對象在derived class構造函數開始執行前不會成爲一個derived class對象。
相同的道理也適用於析構函數。
換句話說,由於你無法使用virtual函數從base class 向下調用, 在構造期間,你可以藉由“令derived class 將必要的構造信息向上傳遞至 base class 構造函數” 替換之二加以彌補。