Effective C 筆記 條款09

2022-03-06 02:25:36 字數 2012 閱讀 6152

)為方便採用書上的例子,先提出問題,在說解決方案。

class transaction;

7:
8: transaction::transaction()                //base class 的建構函式之實現
9:
13:
14:

class buytransaction:public transaction;

假設在程式中:

buytransaction建構函式會被呼叫,但首先transaction的建構函式會被呼叫;derived class物件內的base class成分會在derived class自身成分被構造之前先構造妥當。transaction建構函式最後一行呼叫virtual函式logtransaction是base class內的版本。是的,base class構造期間virtual函式絕對不會下降到derived class階層。即「在base class 構造期間,virtual函式不是virtual函式」。

這一似乎反直覺的行為有個好理由:對於base class建構函式的執行更早於derived class建構函式,當base class建構函式執行時derived class的成員變數尚未初始化。如果此期間呼叫virtual函式下降至derived class階層,要知道derived class的函式幾乎必然取用local成員變數,而那些變數尚未初始化,c++不允許你這樣做。

其實還有更根本的原因:在derived class物件的base class構造期間,物件的型別是derived class。

相同道理也適用於析構函式。一旦derived class析構函式開始執行,物件內的derived class 成員變數便呈現未定義的值。進入base class析構函式後物件就成為乙個base class物件,而virtual函式等也那麼看待它。

另外,偵測「建構函式或析構函式執行期間是否呼叫virtual函式」並不是很輕鬆。唯一能夠避免此問題的做法就是:確定你的建構函式和析構函式都沒有(在物件被建立和被銷毀期間)呼叫virtual函式,而它們呼叫的所有函式也都服從同一約束。

上面提到唯一能夠避免此問題的做法就是:確定你的建構函式和析構函式都沒有(在物件被建立和被銷毀期間)呼叫virtual函式,而它們呼叫的所有函式也都服從同一約束。

但是,如何確保每次一繼承體系上的物件被建立,都有適當版本的函式被呼叫呢?很顯然,在base class建構函式內對著物件呼叫virtual函式是一種錯誤的做法。其他方案可以解決這個問題:一種做法是在class transaction內將logtransaction函式改為non-virtual,然後derived class建構函式傳遞必要的資訊給transaction建構函式,然後那個建構函式便可安全呼叫non-virtual logtransaction:

class transaction;

7: transaction::transaction( const string& loginfo )
8:
11:
12:

class buytransaction:public transaction

16:     ...
17:

private:

18:

static string createlogstring(parameters) ;

19: };
20:

換句話說由於無法使用virtual函式從base class向下呼叫,在建構函式期間,你可以藉由「令derived class將必要的構造資訊傳遞至base class建構函式」替換之而加以補償。

令createlogstring為static,也就不可能意外指向「初期未成熟之buytransaction物件尚未初始化的成員變數」。這很重要,正因為「那些成員變數處於未定義狀態」,所以在「base class構造和析構期間呼叫的virtual函式不可下降至derived class」 。

請注意:在構造和析構期間不要呼叫virtual函式,因為這類呼叫從不下降至derived class。

Effective C 筆記 條款11

為什麼會出現自我賦值呢?不明顯的自我賦值,是 別名 帶來的結果 所謂 別名 就是 有乙個以上的方法指涉物件 一般而言如果某段 操作pointers或references而它們被用來 指向多個相同型別的物件 就需要考慮這些物件是否為同乙個。實際上兩個物件來自同乙個繼承體系,它們甚至不需要宣告為相同型別...

Effective C 筆記 條款08

c 並不禁止析構函式吐出異常,但它不鼓勵你這樣做。考慮如下 class widget 假設這個可能吐出乙個異常5 6 7 void dosomething 8 當vector v被銷毀,它有責任銷毀其內含的所有widgets。銷毀第乙個丟擲異常,銷毀第二個丟擲異常 異常對c 而言太多了。其實,在兩個...

Effective C 筆記 條款07

這個規則只適用於polymorphic 帶多型性質的 base class身上。這種base class的設計目的是為了用來 通過base class介面處理derived class物件 假如我們在程式中設計factory 工廠 函式,讓它返回base class指標,指向新生成的derived ...