[C++] 動態(tài)綁定和靜態(tài)綁定

你不應(yīng)該重新定義一個繼承而來的non-virtual函數(shù)。
為繼承而來的virtual函數(shù)冤吨,重新定義缺省參數(shù)值哑子,也很糟糕。

因為鞋喇,virtual函數(shù)系動態(tài)綁定(dynamically bound)声滥,
而缺省參數(shù)值卻是靜態(tài)綁定(statically bound)。

1. 靜態(tài)類型

對象的所謂靜態(tài)類型(static type)侦香,就是它在程序中被聲明時所采用的類型落塑,
考慮以下的class繼承體系:

// 一個用以描述幾何形狀的class
class Shape{
public:
    enum ShapeColor { Red, Green, Blue };

    // 所有形狀都必須提供一個函數(shù),用來繪制出自己
    virtual void draw(ShapeColor color = Red) const = 0;

    ...
};
class Rectangle: public Shape{
public:
    // 注意罐韩,賦予不同的缺省參數(shù)值憾赁,這真糟糕
    virtual void draw(ShapeColor color = Green) const;

    ...
};

class Circle: public Shape{
public:
    virtual void draw(ShapeColor color) const;
};

現(xiàn)在考慮這些指針:

// 以下三個指針ps,pc,pr的靜態(tài)類型,都是Shape*
Shape* ps;
Shape* pc = new Circle;
Shape* pr = new Rectangle;

2. 動態(tài)類型

對象的所謂動態(tài)類型(dynamic type)則指的是“目前所指對象的類型”散吵,
也就是說龙考,動態(tài)類型可以表現(xiàn)出一個對象將會有什么行為。
以上例而言矾睦,pc的動態(tài)類型是Circle*晦款,pr的動態(tài)類型是Rectangle*,ps沒有動態(tài)類型枚冗,因為它尚未指向任何對象缓溅。

動態(tài)類型一如其名稱所示,可在程序執(zhí)行過程中改變(通常是經(jīng)由賦值動作):

// ps的動態(tài)類型如今是Circle*
ps = pc;

// ps的動態(tài)類型如今是Rectangle*
ps = pr;

virtual函數(shù)系動態(tài)綁定而來赁温,意思是調(diào)用一個virtual函數(shù)時肛宋,究竟調(diào)用哪一份函數(shù)實現(xiàn)代碼州藕,
取決于發(fā)出調(diào)用的那個對象的動態(tài)類型。

// 調(diào)用Circle::draw(Shape::Red)
pc->draw(Shape::Red);

// 調(diào)用Rectangle::draw(Shape::Red)
pr->draw(Shape::Red);

3. 缺省參數(shù)值

但是當(dāng)你考慮帶有缺省參數(shù)值的virtual函數(shù)酝陈,花樣來了,
virtual函數(shù)是動態(tài)綁定毁涉,而缺省參數(shù)值卻是靜態(tài)綁定沉帮。
意思是,你可能會在“調(diào)用一個定義于derived class內(nèi)的virtual函數(shù)”的同時贫堰,卻使用base class為它所指定的缺省參數(shù)值穆壕。

// 調(diào)用Rectangle::draw(Shape::Red)
pr->draw();

此例之中,pr的動態(tài)類型是Rectangle*其屏,所以調(diào)用的是Rectangle的virtual函數(shù)喇勋,一如你所預(yù)期,
Rectangle::draw函數(shù)的缺省參數(shù)值應(yīng)該是Green偎行,但由于pr的靜態(tài)類型是Shape*川背,
所以,此一調(diào)用的缺省參數(shù)值來自Shape class而非Rectangle class蛤袒。
結(jié)局是這個函數(shù)調(diào)用有著奇怪并且?guī)缀踅^對沒人預(yù)料得到的組合熄云,由Shape class和Rectangle class的draw聲明式各出一半力。

以上事實不只局限于“ps,pc和pr都是指針”的情況妙真,即使把指針換成reference問題仍然存在缴允。
重點在于draw是個virtual函數(shù),而它的缺省參數(shù)值在derived class中被重新定義了珍德。

這一切還好练般,但如果你試著遵守這條規(guī)則,并且同時提供缺省參數(shù)值給base和derived class的用戶锈候,又會發(fā)生什么事呢薄料?

class Rectangle: public Shape{
public:
    virtual void draw(ShapeColor color = Red) const;
    ...
};

喔歐,代碼重復(fù)晴及。更糟糕的是都办,代碼重復(fù)又帶有相依性(with dependencies)。
如果Shape內(nèi)的缺省參數(shù)值改變了虑稼,所有的“重復(fù)給定缺省參數(shù)值”的那些derived class也必須改變琳钉,
否則它們最終會導(dǎo)致“重復(fù)定義一個繼承而來的缺省參數(shù)值”。
怎么辦蛛倦?

4. non-virtual interface

當(dāng)你想令virtual函數(shù)表現(xiàn)出你所想要的行為但卻遭遇麻煩歌懒,聰明的做法是考慮替代設(shè)計。
其中之一是NVI(non-virtual interface)手法:
令base class內(nèi)的一個public non-virtual函數(shù)調(diào)用private virtual函數(shù)溯壶,后者可被derived class重新定義及皂。
這里我們可以讓non-virtual函數(shù)指定缺省參數(shù)甫男,而private virtual函數(shù)負(fù)責(zé)真正的工作。

class Shape{
public:
    enum ShapeColor { Red, Green, Blue };

    // 如今它是non-virtual
    void draw(ShapeColor color = Red) const {

        // 調(diào)用一個virtual
        doDraw(color);
    }
    ...

private:
    // 真正的工作在此處完成
    virtual void doDraw(ShapeColor color) const = 0;
};
class Rectangle: public Shape{
public:
    ...

public:
    // 注意验烧,不須制定缺省參數(shù)值
    virtual void doDraw(ShapeColor color) const;
};

由于non-virtual函數(shù)絕對不應(yīng)該被derived class覆寫板驳,這個設(shè)計很清楚的使用draw函數(shù)的color缺省值總是為Red。


Effective C++ - P180

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末碍拆,一起剝皮案震驚了整個濱河市若治,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌感混,老刑警劉巖端幼,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異弧满,居然都是意外死亡婆跑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進(jìn)店門庭呜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滑进,“玉大人,你說我怎么就攤上這事疟赊〗脊” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵近哟,是天一觀的道長驮审。 經(jīng)常有香客問我,道長吉执,這世上最難降的妖魔是什么疯淫? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮戳玫,結(jié)果婚禮上熙掺,老公的妹妹穿的比我還像新娘。我一直安慰自己咕宿,他們只是感情好币绩,可當(dāng)我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著府阀,像睡著了一般缆镣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上试浙,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天董瞻,我揣著相機與錄音,去河邊找鬼田巴。 笑死钠糊,一個胖子當(dāng)著我的面吹牛挟秤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抄伍,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼艘刚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了截珍?” 一聲冷哼從身側(cè)響起昔脯,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎笛臣,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體隧饼,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡沈堡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了燕雁。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诞丽。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拐格,靈堂內(nèi)的尸體忽然破棺而出僧免,到底是詐尸還是另有隱情,我是刑警寧澤捏浊,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布懂衩,位于F島的核電站,受9級特大地震影響金踪,放射性物質(zhì)發(fā)生泄漏浊洞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一胡岔、第九天 我趴在偏房一處隱蔽的房頂上張望法希。 院中可真熱鬧,春花似錦靶瘸、人聲如沸苫亦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屋剑。三九已至,卻和暖如春惊暴,著一層夾襖步出監(jiān)牢的瞬間饼丘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工辽话, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留肄鸽,地道東北人卫病。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像典徘,于是被迫代替她去往敵國和親蟀苛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容