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

洛譯小筑

別來無恙,我的老友…
隨筆 - 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>
            在线午夜精品| 欧美国产一区二区在线观看| 一区二区日韩免费看| 欧美精品在线网站| 亚洲神马久久| 香蕉成人伊视频在线观看| 国产一区二区在线观看免费播放| 久久av一区| 久久婷婷蜜乳一本欲蜜臀| 91久久精品国产91性色| 久久综合网hezyo| 一区二区三区四区五区在线| 亚洲日本视频| 国产精品有限公司| 裸体丰满少妇做受久久99精品| 久热精品视频在线观看| 一区二区欧美激情| 亚洲欧美综合精品久久成人 | 亚洲国产精品黑人久久久| 欧美顶级少妇做爰| 欧美一区二区三区免费观看| 久久激情婷婷| 亚洲视频在线播放| 久久精品亚洲一区| 亚洲图中文字幕| 久久成人综合网| 中文国产亚洲喷潮| 久久久久久电影| 亚洲欧美制服另类日韩| 狼人社综合社区| 欧美一区二区高清| 欧美激情一区在线观看| 久久久久五月天| 欧美三区美女| 亚洲国产经典视频| 国产亚洲精品资源在线26u| 亚洲国产精品一区在线观看不卡| 国产农村妇女精品一二区| 亚洲级视频在线观看免费1级| 国产亚洲欧美激情| 亚洲午夜一区二区三区| 日韩一级网站| 久久久久久久一区二区| 欧美一区不卡| 国产精品草莓在线免费观看| 欧美黄色影院| 一区二区视频免费完整版观看| 亚洲视频网在线直播| 一区二区三区日韩欧美| 久久综合狠狠综合久久综青草 | 国内综合精品午夜久久资源| 亚洲深爱激情| 亚洲一区二区三区视频| 欧美激情在线狂野欧美精品| 欧美成黄导航| 亚洲电影在线| 久久一区国产| 欧美激情在线| 亚洲精品日韩在线观看| 蜜臀va亚洲va欧美va天堂| 六月婷婷久久| 在线观看亚洲视频啊啊啊啊| 久久久久久久999| 老司机午夜精品| 在线观看欧美亚洲| 麻豆av一区二区三区| 欧美黄色一区| 日韩写真在线| 欧美性大战久久久久久久蜜臀 | 久久久久久欧美| 国产有码在线一区二区视频| 欧美一区二区福利在线| 久久免费视频在线观看| 亚洲影音一区| 樱桃成人精品视频在线播放| 久久久久久久成人| 欧美激情aaaa| 亚洲午夜日本在线观看| 国产精品大片免费观看| 亚洲欧美激情四射在线日| 久久av资源网站| 亚洲国产色一区| 9国产精品视频| 国产精品日日摸夜夜摸av| 小嫩嫩精品导航| 欧美aa国产视频| 99re66热这里只有精品3直播| 欧美日韩卡一卡二| 午夜精品久久久久久久99樱桃| 久久久一区二区三区| 亚洲人成人99网站| 国产精品久久久久久久午夜片| 欧美一级日韩一级| 亚洲电影观看| 欧美激情自拍| 亚洲欧美在线免费| 亚洲高清久久久| 欧美一区二区免费视频| 亚洲三级视频| 国产女优一区| 欧美久久一区| 欧美一区二区视频在线观看2020| 亚洲国产日韩在线| 久久久国产视频91| 亚洲桃色在线一区| 在线精品福利| 国产精品美女久久福利网站| 久热精品视频在线观看| 亚洲制服av| 日韩天堂在线观看| 欧美高清在线一区二区| 欧美一级电影久久| 国产精品99久久99久久久二8| 精品91免费| 国产麻豆91精品| 欧美色123| 欧美成人网在线| 久久精品视频在线看| 亚洲欧美日韩国产成人精品影院 | 亚洲天堂偷拍| 亚洲精品乱码久久久久| 国产在线乱码一区二区三区| 国产精品久久久久久久久动漫| 欧美成人精品福利| 久热精品视频在线免费观看| 欧美一级片久久久久久久| 亚洲天堂成人在线视频| 亚洲精品一品区二品区三品区| 欧美不卡高清| 麻豆精品一区二区av白丝在线| 欧美在线视频日韩| 性欧美xxxx大乳国产app| 亚洲一区二区三区精品动漫| 99视频一区二区| 亚洲伦理中文字幕| 99re8这里有精品热视频免费 | 国产精品久久久99| 欧美丝袜第一区| 欧美午夜不卡在线观看免费| 欧美日韩国产a| 欧美日本在线一区| 欧美日韩二区三区| 欧美日韩成人在线观看| 欧美精品一区二| 欧美日韩美女在线观看| 欧美凹凸一区二区三区视频| 亚洲小说春色综合另类电影| 9人人澡人人爽人人精品| 亚洲精品影视| 亚洲永久在线| 欧美亚洲一区| 久久在线免费观看| 欧美激情亚洲视频| 亚洲区欧美区| 在线视频欧美日韩精品| 亚洲欧美视频在线| 久久精品国产亚洲一区二区| 另类图片综合电影| 欧美日本一区二区高清播放视频| 欧美三级中文字幕在线观看| 国产精品日韩欧美大师| 好看的av在线不卡观看| 亚洲人成人99网站| 亚洲一区视频在线| 久久久久久电影| 亚洲国产成人精品女人久久久| 亚洲国产精品一区二区第一页| 亚洲最新视频在线播放| 欧美一区网站| 欧美精品一区二区三区一线天视频| 欧美日韩一级片在线观看| 国产一区二区三区电影在线观看| 伊人成人在线| 亚洲一区二区三区影院| 久久资源在线| 99精品国产热久久91蜜凸| 欧美一乱一性一交一视频| 欧美激情一区二区三区在线视频观看 | 日韩午夜在线电影| 欧美在线国产精品| 欧美日韩国产高清视频| 国产亚洲福利社区一区| 99riav1国产精品视频| 久久av资源网| 日韩网站在线观看| 久久精品99国产精品| 欧美日韩四区| 91久久精品一区二区别| 欧美一区激情| 日韩视频在线一区二区三区| 久久久久九九视频| 国产精品午夜国产小视频| 99精品视频免费观看| 久久综合久久综合这里只有精品| 一本色道久久| 猛干欧美女孩| 在线观看视频一区二区| 久久精品99久久香蕉国产色戒| 一区二区三区四区五区视频| 欧美a级片一区|