<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # Item 37: 絕不要重定義一個函數的 inherited default parameter value(通過繼承得到的缺省參數值) 作者:Scott Meyers 譯者:fatalerror99 (iTePub's Nirvana) 發布:http://blog.csdn.net/fatalerror99/ 我們直接著手簡化這個話題。只有兩種函數能被你 inherit(繼承):virtual(虛擬的)和 non-virtual(非虛擬的)。然而,重定義一個 inherited non-virtual function(通過繼承得到的非虛擬函數)永遠都是一個錯誤(參見 Item 36),所以我們可以安全地將我們的討論限制在你繼承了一個 virtual function with a default parameter value(帶有一個缺省參數值的虛擬函數)的情形。 在這種情況下,本 Item 的理由就變得非常地直截了當:virtual functions(虛擬函數)是 dynamically bound(動態綁定),而 default parameter values(缺省參數值)是 statically bound(靜態綁定)。 那又怎樣呢?你說 static(靜態)和 dynamic binding(動態綁定)之間的區別早已塞入你負擔過重的頭腦?(不要忘了,static binding(靜態綁定)也以 early binding(前期綁定)聞名,而 dynamic binding(動態綁定)也以 late binding(后期綁定)聞名。)那么,我們就再來回顧一下。 一個 object(對象)的 static type(靜態類型)就是你在程序文本中聲明給它的 type(類型)。考慮這個 class hierarchy(類繼承體系): ``` // a class for geometric shapes class Shape { public: enum ShapeColor { Red, Green, Blue }; // all shapes must offer a function to draw themselves virtual void draw(ShapeColor color = Red) const = 0; ... }; class Rectangle: public Shape { public: // notice the different default parameter value — bad! virtual void draw(ShapeColor color = Green) const; ... }; class Circle: public Shape { public: virtual void draw(ShapeColor color) const; ... }; ``` 直觀地看,它看起來就像這個樣子: ![](https://box.kancloud.cn/2015-12-29_56820e4af25a5.gif) 現在考慮這些 pointers(指針): ``` Shape *ps; // static type = Shape* Shape *pc = new Circle; // static type = Shape* Shape *pr = new Rectangle; // static type = Shape* ``` 在本例中,ps,pc 和 pr 全被聲明為 pointer-to-Shape 類型,所以它們全都以此作為它們的 static type(靜態類型)。注意這就使得它們真正指向的東西完全沒有區別——無論如何,它們的 static type(靜態類型)都是 Shape\*。 一個 object(對象)的 dynamic type(動態類型)取決于它當前引用的 object(對象)的 type(類型)。也就是說,它的 dynamic type(動態類型)表明它有怎樣的行為。在上面的例子中,pc 的 dynamic type(動態類型)是 Circle\*,而 pr 的 dynamic type(動態類型)是 Rectangle\*。至于 ps,它沒有一個實際的 dynamic type(動態類型),因為它(還)不能引用任何 object(對象)。 dynamic types(動態類型),就像它的名字所暗示的,能在程序運行中變化,特別是通過 assignments(賦值): ``` ps = pc; // ps's dynamic type is // now Circle* ps = pr; // ps's dynamic type is // now Rectangle* ``` virtual functions(虛擬函數)是 dynamically bound(動態綁定),意味著被調用的特定函數取決于被用來調用它的那個 object(對象)的 dynamic type(動態類型): ``` pc->draw(Shape::Red); // calls Circle::draw(Shape::Red) pr->draw(Shape::Red); // calls Rectangle::draw(Shape::Red) ``` 我知道,這全是老生常談;你的確已經理解了 virtual functions(虛擬函數)。但是,當你考慮 virtual functions with default parameter values(帶有缺省參數值的虛擬函數)時,就全亂了套,因為,如上所述,virtual functions(虛擬函數)是 dynamically bound(動態綁定),但 default parameters(缺省參數)是 statically bound(靜態綁定)。這就意味著你最終調用了一個定義在 derived class(派生類)中的 virtual function(虛擬函數)卻使用了一個來自 base class(基類)的 default parameter value(缺省參數值)。 ``` pr->draw(); // calls Rectangle::draw(Shape::Red)! ``` 在此情況下,pr 的 dynamic type(動態類型)是 Rectangle\*,所以正像你所希望的,Rectangle 的 virtual function(虛擬函數)被調用。在 Rectangle::draw 中,default parameter value(缺省參數值)是 Green。然而,因為 pr 的 static type(靜態類型)是 Shape\*,這個函數調用的 default parameter value(缺省參數值)是從 Shape class 中取得的,而不是 Rectangle class!導致的結果就是一個調用由“奇怪的和幾乎完全出乎意料的 Shape 和 Rectangle 兩個 classes(類)中的 draw 聲明的混合物”所組成。 ps,pc,和 pr 是 pointers(指針)的事實與這個問題并無因果關系,如果它們是 references(引用),問題依然會存在。唯一重要的事情是 draw 是一個 virtual function(虛擬函數),而它的一個 default parameter values(缺省參數值)在一個 derived class(派生類)中被重定義。 為什么 C++ 要堅持按照這種不正常的方式動作?答案是為了運行時效率。如果 default parameter values(缺省參數值)是 dynamically bound(動態綁定),compilers(編譯器)就必須提供一種方法在運行時確定 virtual functions(虛擬函數)的 parameters(參數)的 default value(s)(缺省值),這比目前在編譯期確定它們的機制更慢而且更復雜。最終的決定偏向了速度和實現的簡單這一邊,而造成的結果就是你現在可以享受高效運行的樂趣,但是,如果你忘記留心本 Item 的建議,就會陷入困惑。 這樣就很徹底而且完美了,但是看看如果你試圖遵循本規則為 base(基類)和 derived classes(派生類)的用戶提供同樣的 default parameter values(缺省參數值)時會發生什么: ``` 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; ... }; ``` 噢,code duplication(代碼重復)。code duplication(代碼重復)帶來 dependencies(依賴關系):如果 Shape 中的 default parameter values(缺省參數值)發生變化,所有重復了它的 derived classes(派生類)必須同時變化。否則它們就陷入重定義一個 inherited default parameter value(通過繼承得到的缺省參數值)。怎么辦呢? 當你要一個 virtual function(虛擬函數)按照你希望的方式運行有困難的時候,考慮可選的替代設計是很明智的,而且 Item 35 給出了多個 virtual function(虛擬函數)的替代方法。替代方法之一是 non-virtual interface idiom (NVI idiom)(非虛擬接口慣用法):用 base class(基類)中的 public non-virtual function(公有非虛擬函數)調用 derived classes(派生類)可能重定義的 private virtual function(私有虛擬函數)。這里,我們用 non-virtual function(非虛擬函數)指定 default parameter(缺省參數),同時使用 virtual function(虛擬函數)做實際的工作: ``` class Shape { public: enum ShapeColor { Red, Green, Blue }; void draw(ShapeColor color = Red) const // now non-virtual { doDraw(color); // calls a virtual } ... private: virtual void doDraw(ShapeColor color) const = 0; // the actual work is }; // done in this func class Rectangle: public Shape { public: ... private: virtual void doDraw(ShapeColor color) const; // note lack of a ... // default param val. }; ``` 因為 non-virtual functions(非虛擬函數)絕不應該被 derived classes(派生類) overridden(覆蓋)(參見 Item 36),這個設計使得 draw 的 color parameter(參數)的 default value(缺省值)應該永遠是 Red 變得明確。 Things to Remember 絕不要重定義一個 inherited default parameter value(通過繼承得到的缺省參數值),因為 default parameter value(缺省參數值)是 statically bound(靜態綁定),而 virtual functions ——應該是你可以 overriding(覆蓋)的僅有的函數——是 dynamically bound(動態綁定)。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看