EffectiveC 學習筆記 條款36 37

2021-08-04 08:16:21 字數 1673 閱讀 8034

條款36 決不重新定義繼承而來的non-virtual函式

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

正常情況下non-virtual的函式就應該是被設計的目的之一就是為了不能讓子類重寫。

看個簡單例子:

class base

};class derived : public base

};int main()

return0;}

//列印結果

base:print

base:print

這應該不是我們想要的結果,如果是non-virtual一定不要重寫,需要重寫的不要設計成non-virtual。

這個情況出現的次數可能不多,但是有一些需要關注的地方,例如:

//基類

class shape

; virtual

void drawcolor(colortype type = red) const = 0;

};class rect : public shape

};class circle : public shape

};int main()

//列印結果 兩個子類的列印結果都是 0 也就是red

drawcolor:0

drawcolor:0

回顧一下虛函式的知識,如果父類中存在有虛函式,那麼編譯器便會為之生成虛表與虛指標,在程式執行時,根據虛指標的指向,來決定呼叫哪個虛函式,這稱之與動態繫結,與之相對的是靜態繫結,靜態繫結在編譯期就決定了。

實現動態繫結的代價是比較大的,所以編譯器在函式引數這部分,並沒有採用動態繫結的方式,也就是說,預設的形參是靜態繫結的,它是編譯期就決定下來了。

rect的靜態型別是shape*,動態型別才是rect*,類似地,circle的靜態型別是shape*,動態型別是circle*。這裡沒有帶引數,所以使用的是預設的形參,即為靜態的shape::drawcolor()裡面的預設值red,所以兩個問題所在處的輸出值都是0(也就是red)。

正因為編譯器並沒有對形參採用動態繫結,所以如果對繼承而來的虛函式使用不同的預設值,將會給讀者帶來極大的困惑,試想一下下面兩行**:

shape *rect = new rect(); // 預設值是red

rect *rect_temp = new rect(); // 預設值是green

解決辦法

有問題就會有解決方法:

我們可以使用non-virtual呼叫virtual函式。

//基類

class shape

; void draw(colortype type = red) const

//子類不必實現該函式

private:

//真正處理工作的地方

virtual

void

drawcolor(colortype type) const = 0;

};class rect : public shape

};class circle : public shape

};int main()

這樣繼承得到的子類的預設引數都是red。

Effective C 學習筆記

學習effective c 已經有相當長的一段時間了,今天抽出時間又堵了一遍第一部分 c語言 c 以c語言為基礎,幾乎支援所有的c語言成分,例如區塊 語句 預處理 內建資料型別 陣列 指標等,c語言的侷限是 沒有模板 沒有異常 沒有過載 物件導向的c 也就是加上了物件特性的c,類 封裝 繼承 多型 ...

Effective C 學習筆記

1 c 是乙個複合式的語言 c 中不同部分有著不同的語言特性,例如 1.1 在c中傳遞形參時,按照值傳遞比按照指標傳遞效率更高 1.2 在物件導向程式中,物件要按照const引用而不是按照值傳遞 1.3 在stl程式設計中採取按照值傳遞方式 所以說c 中沒有統一的準則,要按照不同的特性採取不同的使用...

effective c 學習筆記

如果不考慮應用程式的使用場合,僅僅考慮語言的靈活性,我贊成作者的想法。但是不同的應用它會有不同的效能要求,所以語言的選擇,應該是用 最適合 條款去選擇。使用巨集定義常量,若定義在標頭檔案中,則所有包含標頭檔案的都可以使用。巨集定義,在預處理的時候進行替換。巨集定義一些簡單的函式,可以減少呼叫開銷,但...