青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

洛譯小筑

別來無恙,我的老友…
隨筆 - 45, 文章 - 0, 評論 - 172, 引用 - 0
數據加載中……

[ECPP讀書筆記 條目37] 避免對函數中繼承得來的默認參數值進行重定義

讓我們開門見山的討論本話題:可以繼承的函數可以分為兩種:虛擬的和非虛擬的。然而,由于重定義一個派生的非虛函數始終是一個錯誤(參見條目36),因此我們可以放心地將此處的討論范圍縮小至以下情況:繼承一個含有默認參數值的函數。

此情況下,證明本條目的結論非常簡單:虛函數是動態綁定的,而默認參數值是靜態綁定的。

你說啥?靜態綁定與動態綁定之間的區別已經讓你頭暈目眩了?(眾所周知,靜態綁定又稱早期綁定,動態綁定又稱晚期綁定。)我們只好復習一下了。

一個對象的靜態類型就是你在對其進行聲明時賦予它的類型。請考慮下面的類層次結構: 

// 幾何形狀類

class Shape {

public:

  enum ShapeColor { Red, Green, Blue };

 

  // 所有形狀必須提供一個自我繪制函數
  virtual void draw(ShapeColor color = Red) const = 0;

  ...

};

 

class Rectangle: public Shape {

public:

  // 請注意:默認參數值變了——糟糕!

  virtual void draw(ShapeColor color = Green) const;

  ...

};

 

class Circle: public Shape {

public:

  virtual void draw(ShapeColor color) const;

  ...

};

用UML來表示:


現在請考慮下面的指針:

Shape *ps;                        // 靜態類型 = Shape*

Shape *pc = new Circle;           // 靜態類型 = Shape*

Shape *pr = new Rectangle;        // 靜態類型 = Shape*

示例中,由于pspc以及pr都聲明為指向Shape的指針,因此他們的靜態類型均為Shape*。請注意,這樣做使得無論他們實際指向的對象是什么類型,他們的靜態類型都必為Shape*

對象的動態類型是通過他當前引用的對象的類型決定的。也就是說,動態類型表明了他應具有怎樣的行為。在上文的示例中,pc的動態類型是Circle*pr的動態類型是Rectangle*。而對于ps來說,他在當前根本不具備動態類型,因為它(目前)還沒有引用任何對象呢。

動態類型,顧名思義,在程序運行時可能會有所改變,通常是通過賦值操作發生: 

ps = pc;                           // ps動態類型變為Circle*

ps = pr;                           // ps動態類型變為Rectangle*

虛函數是動態綁定的,這就意味著,對于一個特定的函數調用,其調用對象的動態類型將決定調用這一函數的哪個版本: 

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

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

我知道這些都是老生常談了,你當然已經對虛函數有了透徹的理解。只有在虛函數包含默認參數值時,情況才有所不同。這是因為(如上文所述),虛函數是動態綁定的,但是默認參數是靜態綁定的。這也就意味著對于一個虛函數,你可能會調用它在派生類中的定義,而默認參數值則采用基類中的值: 

pr->draw();                   // 調用 Rectangle::draw(Shape::Red)!

這種情況下,由于pr的動態類型是Rectangle*,于是此處便調用了虛函數drawRectangle版本,正如你所愿。在Rectangle::draw中,默認參數值是Green。然而,因為pr的靜態類型是Shape*,這里的draw調用將采用Shape類中的默認參數值,而不是Rectangle!最終,在Shape類和Rectangle類之間,對于draw的調用必將出現混亂的無法預知的現象。

雖然pspcpr是指針,但是并不影響上文的結論。如果它們是引用的話,問題同樣存在。這里只有一個重點:draw是虛函數,他的一個默認參數值在派生類中被重定義了。

是什么讓C++在處理這一問題時如此不合常理? 答案是:運行時效率。如果默認參數值是動態綁定的話,那么編譯器必須提供一整套方案,為運行時的虛函數參數確定恰當的默認值。而這樣做,比起C++當前使用的編譯時決定機制而言,將會更復雜、更慢。魚和熊掌不可兼得,C++將設計的中心傾向了速度和簡潔,你在享受效率的快感的同時,如果你忽略本條目的建議,你就會陷入困惑。

一切看上去似乎盡善盡美了,但是一旦你不假思索的遵守本條建議,為基類和派生類分別提供默認參數值的話,看看將會發生什么: 

class Shape {

public:

  enum ShapeColor { Red, Green, Blue };

 

  virtual void draw(ShapeColor color = Red) const = 0;

  ...

};

class Rectangle: public Shape {

public:

  virtual void draw(ShapeColor color = Red) const;

  ...

};

 吁……惱人的重復代碼。還有更糟的:這些重復代碼彼此還有依賴:如果Shape中的默認參數值改變了的話,那么所有的派生類中相應的值都必須改變。否則這些函數仍將改變繼承來的默認參數值。那么怎么辦呢?

遇到麻煩了?虛函數無法按照你預想的方式運行?這時候明智的做法是:考慮一個替代的設計方案,條目35中介紹了幾種虛函數的替代方案。其中一種是非虛擬接口慣用法方案(NVI慣用法):在基類中用一個公有的非虛函數調用一個私有的虛函數,并在派生類中重定義這一虛函數。在這里,我們將默認參數置于非虛函數中,讓虛函數做具體的工作。

class Shape {

public:

  enum ShapeColor { Red, Green, Blue };

 

  void draw(ShapeColor color = Red) const

  {                                // 現在draw是非虛函數

doDraw(color);                 // 調用一個虛函數

  }

 ... 

private:

  virtual void doDraw(ShapeColor color) const = 0;

                                   // 這個函數做真正的工作

};

 

class Rectangle: public Shape {

public:

  ...

private:
  virtual void doDraw(ShapeColor color) const; 

                                   //此處不需要默認參數值
  ...

};

 由于在派生類中不能對非虛函數進行重載(參見條目36),因此,顯然地,這一設計方案使得draw函數中color參數的默認值永遠為Red


時刻牢記

避免在對函數中繼承得來的默認參數值進行重定義,這是因為默認參數值是靜態綁定的,而虛函數(派生類中唯一的一系列可以重定義的函數)是動態綁定的。

posted on 2012-05-20 11:21 ★ROY★ 閱讀(2135) 評論(0)  編輯 收藏 引用 所屬分類: Effective C++

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            999在线观看精品免费不卡网站| 久久精品国产成人| 午夜久久一区| 午夜精品久久久久久久99热浪潮 | 你懂的视频欧美| 久久九九热免费视频| 久久一区二区三区四区| 欧美高清视频在线播放| 亚洲精品国产欧美| 日韩视频永久免费| 亚洲视屏一区| 久久只精品国产| 欧美激情亚洲综合一区| 国产精品久久91| 怡红院精品视频在线观看极品| 亚洲国产精品悠悠久久琪琪| 99人久久精品视频最新地址| 亚洲欧美一区二区三区久久 | 欧美精品日本| 国产精品专区h在线观看| 极品尤物久久久av免费看| 99re热精品| 久久精品1区| 亚洲人成亚洲人成在线观看图片 | 在线一区二区日韩| 99视频+国产日韩欧美| 尤物yw午夜国产精品视频明星| 欧美人妖另类| 国内精品久久久久影院优| 亚洲精品欧美日韩| 欧美在线视频免费播放| 亚洲国产成人一区| 新67194成人永久网站| 欧美国产日本| 国产视频久久| 亚洲视频一二区| 欧美成人国产一区二区| 亚洲图片在线观看| 欧美精品亚洲二区| 亚洲盗摄视频| 久久精品国产亚洲高清剧情介绍| 亚洲日韩欧美视频一区| 久久国产精品99精品国产| 国产精品久久久久久久久久久久久| 影音先锋久久精品| 久久国产精品电影| 亚洲自拍啪啪| 国产精品社区| 亚洲在线观看视频网站| 亚洲靠逼com| 欧美精品一区二区三区一线天视频| 黄色精品一二区| 久久国产主播精品| 午夜一区二区三区在线观看| 欧美亚洲第一页| 亚洲私人黄色宅男| 一区二区高清视频| 欧美日韩日日夜夜| 一区二区三区www| 日韩一级黄色片| 欧美视频专区一二在线观看| 亚洲免费大片| 最新成人av在线| 欧美极品在线播放| av不卡在线观看| 日韩视频免费看| 国产精品黄视频| 欧美一区二区三区精品 | 亚洲经典自拍| 久久人人爽国产| 亚洲激情视频| 亚洲美女精品久久| 国产精品丝袜白浆摸在线| 亚洲免费一在线| 欧美亚洲三区| 亚洲福利视频三区| 最新国产成人在线观看| 欧美午夜无遮挡| 久久精品色图| 老牛国产精品一区的观看方式| 亚洲成在线观看| 亚洲美女免费精品视频在线观看| 欧美三区在线视频| 久久久久久电影| 久久精品国产久精国产爱| 西西人体一区二区| 亚欧成人在线| 亚洲精品国产精品乱码不99| 亚洲精品中文字| 国产九九精品| 欧美激情国产日韩| 国产精品v片在线观看不卡| 欧美一区影院| 欧美高清一区| 欧美一区二区三区在| 欧美中文字幕视频| 亚洲美女毛片| 亚洲欧美激情一区| 亚洲三级电影在线观看| 亚洲欧美成人精品| 亚洲国产一区在线| 亚洲婷婷综合久久一本伊一区| 在线电影国产精品| 一区二区三区欧美在线观看| 精品电影在线观看| 亚洲色图制服丝袜| 亚洲国产天堂久久国产91| 亚洲性夜色噜噜噜7777| 亚洲黄色天堂| 久久久久久久久伊人| 亚洲欧美电影院| 欧美国产激情| 欧美二区在线播放| 国产亚洲成av人片在线观看桃| 最新精品在线| 亚洲高清在线视频| 久久www免费人成看片高清| 亚洲香蕉网站| 欧美日韩播放| 亚洲国产精品一区二区久| 国产一区二区三区免费不卡 | 1024成人网色www| 亚洲欧美一区二区精品久久久| 亚洲精品久久久久久下一站| 久久精品成人欧美大片古装| 性高湖久久久久久久久| 欧美日韩国产色综合一二三四| 久热精品在线视频| 国精品一区二区| 久久精品首页| 久久综合一区| 亚洲大胆女人| 久久野战av| 美日韩免费视频| 在线电影院国产精品| 久久国产手机看片| 久久三级视频| 尤物99国产成人精品视频| 久久久久久久999| 免费短视频成人日韩| 伊人成人开心激情综合网| 久久精品视频在线看| 狂野欧美激情性xxxx| 亚洲国产精品一区二区第四页av | 欧美日韩一区二区三区在线看| 欧美电影电视剧在线观看| 精品成人在线观看| 久久偷看各类wc女厕嘘嘘偷窃| 噜噜噜久久亚洲精品国产品小说| 激情欧美一区二区三区在线观看| 久久免费视频一区| 亚洲电影下载| 夜夜嗨av一区二区三区网站四季av| 欧美日韩精品欧美日韩精品| 一本色道久久| 久久精品国产亚洲aⅴ| 娇妻被交换粗又大又硬视频欧美| 每日更新成人在线视频| 亚洲伦理网站| 久久久九九九九| 亚洲片区在线| 国产精品久久久久久久久久三级| 亚洲欧美日韩区| 亚洲第一天堂av| 亚洲欧美国产77777| 狠狠色综合日日| 欧美日韩国产123区| 亚洲欧美日韩天堂| 亚洲第一精品福利| 午夜国产精品视频| 亚洲电影免费在线| 欧美性jizz18性欧美| 久久精品国产96久久久香蕉| 亚洲欧洲三级| 久久人人97超碰人人澡爱香蕉| 亚洲人成艺术| 国产一区高清视频| 欧美精品一区在线观看| 欧美一区二区三区四区在线| 亚洲日本中文字幕| 巨乳诱惑日韩免费av| 亚洲精一区二区三区| 国产日韩欧美| 欧美日韩高清在线观看| 久久精品一区二区三区不卡| 夜夜躁日日躁狠狠久久88av| 蜜乳av另类精品一区二区| 亚洲制服av| 日韩视频中文字幕| 一区在线电影| 国产一区二区久久久| 国产精品第十页| 欧美bbbxxxxx| 久久日韩精品| 欧美在线网站| 午夜一区二区三区在线观看| 99国产精品| 亚洲精品免费在线播放| 牛夜精品久久久久久久99黑人| 欧美一级欧美一级在线播放|