絕不在構造和析構過程中調用virtual函數

字號:

首先明確一下,對于一個繼承體系,構造函數是從基類開始調用了,而析構函數則正好相反,從最外層的類開始。
    對于在構造函數中調用virtual函數,先舉個例子:
    1 class Transaction //所有交易的基類
    2 {
    3 public:
    4   Transaction();
    5   virtual void logTransaction() const = 0;//日志記錄,因交易類型的不同而有不同的記錄
    6 }
    7
    8 Transaction::Transaction()//構造函數實現
    9 {
    10
    11   logTransaction();//調用了日志記錄
    12 }
    13
    14 class Sell: public Transaction
    15 {
    16 public:
    17   virtual void logTransaction() const;
    18
    19 }
    Sell類從基類中繼承,這時候如果執(zhí)行:
    1 Sell a; //派生類
    則首先會執(zhí)行Transaction的構造函數,而Transaction構造函數會調用Transaction版本加入收藏的logTransaction函數(記?。夯悩嬙旌瘮抵械膙irtual函數不會下降到派生類中)。
    而大家都知道,基類中的logTransaction還沒有實現代碼,這顯然會產生一個連接錯誤。
    有如下的解決方法:將logTransaction聲明為非virtual函數,然后通過派生類向基類傳遞參數的方法來實現。
    1 class Transaction
    2 {
    3 public:
    4   Transaction(const std::string& logInfo);
    5   void logTransaction(const std::string& logInfo) const;//改成非virtual實現
    6
    7 };
    8
    9 Transaction::Transaction(const std::string& logInfo)
    10 {
    11
    12   logTransaction(logInfo);//同樣在構造函數中調用
    13 }
    14
    15 class Sell: public Transaction
    16 {
    17 public:
    18   Sell()
    19     :Transaction(createLog())//將log信息傳給基類構造函數
    20   {
    21
    22   }
    23 }
    如此一來,就是派生類將構造信息向上傳給基類構造函數,解決了這個問題。