經驗:在構造和析構期間不要調用virtual函數,因為這類調用從不下降至derived class(比起當前執行構造函數和析構函數的那層)
示例:
#include#include using namespace std; class Transaction{ //所有交易的base class public: Transaction(){logTransaction();}// 最後動作是記錄這筆交易 virtual void logTransaction() const = 0; //做出一份因類型不同而不同的日志記錄 }; class BuyTransaction: public Transaction{ // derived class public: virtual void logTransaction() const { cout << BuyTransaction << endl; // 記錄此類型的交易 } }; class SellTransaction: public Transaction{ // derived class public: virtual void logTransaction() const { cout << SellTransaction << endl; // 記錄此類型的交易 } }; int main(){ BuyTransaction b; system(pause); }
輸出:
(鏈接出錯)
解析:
不會輸出BuyTransaction,因為在derived class對象在base class 構造期間,對象的類型是base class,所以這裡調用的是Transaction的logTransaction。
而因為Transaction的logTransaction沒有實現,這裡會出現鏈接錯誤。
總結,derived class對象在base class構造期間(此時對象還沒有derived class部分),對象的類型是base class;
derived class 對象在base class析構期間(此時對象的derived class部分已被析構),對象的類型是base class;
糾正:讓derived class將必要的構造信息向上傳遞至base class構造函數
#include#include using namespace std; class Transaction{ //所有交易的base class public: explicit Transaction(const std::string &logInfo); void logTransaction(const std::string &logInfo) const; //如今是個non-virtual函數 }; Transaction::Transaction(const std::string &logInfo){ // base class 構造函數的實現 //... logTransaction(logInfo); // 最後動作是記錄這筆交易 } void Transaction::logTransaction(const std::string &logInfo) const{ cout << logInfo << endl; } class BuyTransaction: public Transaction{ // derived class public: BuyTransaction():Transaction(BuyTransaction){} }; class SellTransaction: public Transaction{ // derived class public: SellTransaction():Transaction(SellTransaction){} }; int main(){ BuyTransaction b; system(pause); }
輸出:
BuyTransaction