條款37 決不要重新定義繼承而來的非虛函式

2022-03-17 19:21:42 字數 921 閱讀 7988

class

b ;class d: public b ;

甚至對b,d或mf一無所知,也可以定義乙個型別d的物件x,

d x;                          // x是型別d的乙個物件

那麼,如果發現這麼做:

b *pb = &x;                   // 得到x的指標

pb->mf();                     // 通過指標呼叫mf

和下面這麼做的執行行為不一樣:

d *pd = &x;                   // 得到x的指標

pd->mf();                     // 通過指標呼叫mf

你一定就會感到很驚奇。

如果mf是非虛函式而d又定義了自己的mf版本,行為就不會相同:

class d: public

b ;pb->mf(); //

呼叫b::mf

pd->mf(); //

呼叫d::mf

名字查詢與繼承:(函式呼叫步驟)

假設呼叫p->mem()

1.首先確定p的靜態型別

2.在p的靜態型別對應的類中查詢,如果找不到,則依次在直接基類中不斷查詢直至到達繼承鏈的頂端,如果找遍了該類及其基類仍然找不到,編譯器將報錯

3.一旦找到mem,就進行常規的型別檢查,以確認對於當前找到的mem,本次呼叫是否合法

4.假設呼叫合法,則編譯器根據呼叫的是否是虛函式而產生不同的**:

如果mem是虛函式且我們是通過引用或指標進行的呼叫,則編譯器產生的**將在執行時確定到底執行該虛函式的哪個版本,依據是物件的動態型別;

反之,則編譯器將產生乙個常規函式呼叫,即靜態繫結

條款37 絕不要重新定義繼承而來的預設引數值

總結 不要重新定義乙個繼承而來的預設引數值,因為 預設引數值是靜態繫結 而virtual函式 你唯一應該覆寫的東西 是動態繫結。我們應該知道,virtual函式是動態繫結 dynamically bound 預設引數值卻是靜態繫結 statically bound 物件的靜態型別 static ty...

決不要重新定義繼承而來的非虛函式

有兩種方法來看待這個問題 理論的方法和實踐的方法。讓我們先從實踐的方法開始。畢竟,理論家一般都很耐心。假設類d公有繼承於類b,並且類b中定義了乙個公有成員函式mf。mf的引數和返回型別不重要,所以假設都為void。換句話說,我這麼寫 class b class d public b 甚至對b,d或m...

條款37 絕不重新定義繼承而來的預設引數值

條款37 絕不重新定義繼承而來的預設引數值 靜態繫結就是在程式中被宣告時所採用的型別 includeusing namespace std class shape virtual void draw shapecolor color red const 0 class rectangle publi...