<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國際加速解決方案。 廣告
                條款12:使用override關鍵字聲明覆蓋的函數 ========================= `C++`中的面向對象的變成都是圍繞類,繼承和虛函數進行的。其中最基礎的一部分就是,派生類中的虛函數會覆蓋掉基類中對應的虛函數。但是令人心痛的意識到虛函數重載是如此容易搞錯。這部分的語言特性甚至看上去是按照墨菲準則設計的,它不需要被遵從,但是要被膜拜。 因為覆蓋“`overriding`”聽上去像重載“`overloading`”,但是它們完全沒有關系,我們要有一個清晰地認識,虛函數(覆蓋的函數)可以通過基類的接口來調用一個派生類的函數: ```cpp class Base{ public: virtual void doWork(); // 基類的虛函數 ... }; class Derived: public Base{ public: virtual void doWork(); // 覆蓋 Base::doWork // ("virtual" 是可選的) ... }; std::unique_ptr<Base> upb = // 產生一個指向派生類的基類指針 // 關于 std::make_unique 的信息參考條款21 std::make_unique<Derived>(); ... upb->doWork(); // 通過基類指針調用 doWork(), // 派生類的對應函數別調用 ``` 如果要使用覆蓋的函數,幾個條件必須滿足: - 基類中的函數被聲明為虛的。 - 基類中和派生出的函數必須是完全一樣的(出了虛析構函數)。 - 基類中和派生出的函數的參數類型必須完全一樣。 - 基類中和派生出的函數的常量特性必須完全一樣。 - 基類中和派生出的函數的返回值類型和異常聲明必須使兼容的。 以上的約束僅僅是`C++98`中要求的部分,`C++11`有增加了一條: - 函數的引用修飾符必須完全一樣。成員函數的引用修飾符是很少被提及的`C++11`的特性,所以你之前沒有聽說過也不要驚奇。這些修飾符使得將這些函數只能被左值或者右值使用成為可能。成員函數不需要聲明為虛就可以使用它們: ```cpp class Widget{ public: ... void doWork() &; // 只有當 *this 為左值時 // 這個版本的 doWorkd() // 函數被調用 void doWork() &&; // 只有當 *this 為右值 // 這個版本的 doWork() // 函數被調用 }; ... Widget makeWidget(); // 工廠函數,返回右值 Widget w; // 正常的對象(左值) ... w.doWork(); // 為左值調用 Widget::doWork() //(即 Widget::doWork &) makeWidget().doWork(); // 為右值調用 Widget::doWork() //(即 Widget::doWork &&) ``` 稍后我們會更多介紹帶有引用修飾符的成員函數的情況,但是現在,我們只是簡單的提到:如果一個虛函數在基類中有一個引用修飾符,派生類中對應的那個也必須要有完全一樣的引用修飾符。如果不完全一樣,派生類中的聲明的那個函數也會存在,但是它不會覆蓋基類中的任何東西。 對覆蓋函數的這些要求意味著,一個小的錯誤會產生一個很大不同的結果。在覆蓋函數中出現的錯誤通常還是合法的,但是它導致的結果并不是你想要的。所以當你犯了某些錯誤的時候,你并不能依賴于編譯器對你的通知。例如,下面的代碼是完全合法的,乍一看,看上去也是合理的,但是它不包含任何虛覆蓋函數——沒有一個派生類的函數綁定到基類的對應函數上。你能找到每種情況里面的問題所在嗎?即為什么派生類中的函數沒有覆蓋基類中同名的函數。 ```cpp class Base { public: virtual void mf1() const; virtual void mf2(int x); virtual void mf3() &; void mf4() const; }; class Derived: public Base { public: virtual void mf1(); virtual void mf2(unsigned int x); virtual void mf3() &&; void mf4() const; }; ``` 需要什么幫助嗎? - `mf1`在`Base`中聲明常成員函數,但是在`Derived`中沒有 - `mf2`在`Base`中以`int`為參數,但是在`Derived`中以`unsigned int`為參數 - `mf3`在`Base`中有左值修飾符,但是在`Derived`中是右值修飾符 - `mf4`沒有繼承`Base`中的虛函數 你可能會想,“在實際中,這些代碼都會觸發編譯警告,因此我不需要過度憂慮。”也許的確是這樣,但是也有可能不是這樣。經過我的檢查,發現在兩個編譯器上,上邊的代碼被全然接受而沒有發出任何警告,在這兩個編譯器上所有警告是都會被輸出的。(其他的編譯器輸出了這些問題的警告信息,但是輸出的信息也不全。) 因為聲明派生類的覆蓋函數是如此重要,有如此容易出錯,所以`C++11`給你提供了一種可以顯式的聲明一個派生類的函數是要覆蓋對應的基類的函數的:聲明它為`override`。把這個規則應用到上面的代碼得到下面樣子的派生類: ```cpp class Derived: public Base { public: virtual void mf1() override; virtual void mf2(unsigned int x) override; virtual void mf3() && override; virtual void mf4() const override; }; ``` 這當然是無法通過編譯的,因為當你用這種方式寫代碼的時候,編譯器會把覆蓋函數所有的問題揭露出來。這正是你想要的,所以你應該把所有覆蓋函數聲明為`override`。 使用`override`,同時又能通過編譯的代碼如下(假設目的就是`Derived`類中的所有函數都要覆蓋`Base`對應的虛函數): ```cpp class Base { public: virtual void mf1() const; virtual void mf2(int x); virtual void mf3() &; virtual void mf4() const; }; class Derived: public Base { public: virtual void mf1() const override; virtual void mf2(int x) override; virtual void mf3() & override; void mf4() const override; // 加上"virtual"也可以 // 但是不是必須的 }; ``` 注意在這個例子中,代碼能正常工作的一個基礎就是聲明`mf4`為`Base`類中的虛函數。絕大部分關于覆蓋函數的錯誤發生在派生類中,但是也有可能在基類中有不正確的代碼。 對于派生類中覆蓋體都聲明為`override`不僅僅可以讓編譯器在應該要去覆蓋基類中函數而沒有去覆蓋的時候可以警告你。它還可以幫助你預估一下更改基類里的虛函數的標識符可能會引起的后果。如果在派生類中到處使用了`override`,你可以改一下基類中的虛函數的名字,看看這個舉動會造成多少損害(即,有多少派生類無法通過編譯),然后決定是否可以為了這個改動而承受它帶來的問題。如果沒有`override`,你會希望此處有一個無所不包的測試單元,因為,正如我們看到的,派生類中那些原本被認為要覆蓋基類函數的部分,不會也不需要引發編譯器的診斷信息。
                  <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>

                              哎呀哎呀视频在线观看