C++11學習筆記(5) —— override and final

1.簡介

C++爲我們提供了繼承和虛函數的重寫特性。 在派生類中,重寫虛函數不強制要求使用 virtual 關鍵字,並且C++並沒有要求強制檢查虛函數的重寫是否真正覆蓋了基類的虛函數,因爲在派生類中,也可以增添新的虛函數,以供下一級的派生類重寫。由於檢查的不夠嚴謹,就有可能產生錯誤。

2.有可能產生的錯誤

最常見的錯誤就是派生類想要重寫基類的虛函數,但是由於參數類型的不同,導致結果和預期不同,例如:

  1. #include"stdafx.h"  
  2. #include<iostream>  
  3.   
  4. using namespace std;  
  5.   
  6. class BaseClass  
  7. {  
  8. public:  
  9.     BaseClass(){}  
  10.     ~BaseClass(){}  
  11. public:  
  12.     virtual void func(int param) { cout << "BaseClass::func. param = "  << param <<endl; }  
  13.     virtual void func2() const { cout<< "BaseClass::func2."<<endl;}  
  14. };  
  15.   
  16. class DeriveClass : public BaseClass  
  17. {  
  18. public:  
  19.     DeriveClass(){}  
  20.     ~DeriveClass(){}  
  21. public:  
  22.     virtual void func(float param) { cout << "DeriveClass::func. param = "  << param <<endl; }  
  23.     virtual void func2() { cout<< "DeriveClass::func2."<<endl;}  
  24. };  
  25.   
  26. int main()  
  27. {  
  28.     BaseClass* pBase = new BaseClass();  
  29.     pBase->func(1);  
  30.     pBase->func2();  
  31.   
  32.     cout<<endl;  
  33.   
  34.     DeriveClass* pDerive = new DeriveClass();  
  35.     pDerive->func(4);  
  36.     pDerive->func2();  
  37.   
  38.     cout<<endl;  
  39.   
  40.     BaseClass* pTest = new DeriveClass();  
  41.     pTest->func(5);  
  42.     pTest->func2();  
  43.   
  44.     cout<<endl;  
  45.   
  46.     system("pause");  
  47.     return 0;  
  48. }  

輸出結果爲


對於函數func,派生類和基類的參數類型不同,雖然函數的返回值和函數名相同,並使用了virtual進行虛函數的聲明,但實際上派生類並沒有重寫基類的虛函數,而是定義了自己的虛函數。使用const 進行限定也是一樣,在基類中func2 爲 const 函數,而派生類沒有 const 進行限定,因此,派生類也並沒有重寫基類的虛函數。 pTest 的輸出結果和我們原本預期的並不相同,其調用的是基類的虛函數。由上圖輸出結果可以看出。

3. override

爲了避免上述問題的發生,C++11增添了override, override並不是一個關鍵字,而是一個用於標記虛函數重寫的標識符,使用override 標記的類成員函數表示我們希望其重寫基類相對應的虛函數。如果沒有重寫,編譯器會報錯。例如:

  1. class BaseClass  
  2. {  
  3. public:  
  4.     BaseClass(){}  
  5.     ~BaseClass(){}  
  6. public:  
  7.     virtual void func(int param) { cout << "BaseClass::func. param = "  << param <<endl; }  
  8.     virtual void func2() const { cout<< "BaseClass::func2."<<endl;}  
  9. };  
  10.   
  11. class DeriveClass : public BaseClass  
  12. {  
  13. public:  
  14.     DeriveClass(){}  
  15.     ~DeriveClass(){}  
  16. public:  
  17.     //error C3668: 'DeriveClass::func' : method with override specifier 'override' did not override any base class methods  
  18.     virtual void func(float param) override { cout << "DeriveClass::func. param = "  << param <<endl; }  
  19.   
  20.     //error C3668: 'DeriveClass::func2' : method with override specifier 'override' did not override any base class methods  
  21.     virtual void func2() override { cout<< "DeriveClass::func2."<<endl;}  
  22. };  

對DeriveClass 的兩個成員函數使用了 override ,編譯器知道我們期望重寫基類的虛函數,但是由於基類並沒有相匹配的虛函數,因此編譯出錯,出錯信息如上述註釋部分所示。

4.final

在一些情況下,我們並不希望某個成員函數再被任何派生類所繼承,在java語言中,有final來進行限定,C++11也提供了 final (同 override一樣不是關鍵字,只是特殊的標識符)。通過使用final對虛函數的限定,任何子類不能重寫該函數,例如:

  1. class BaseClass  
  2. {  
  3. public:  
  4.     BaseClass(){}  
  5.     ~BaseClass(){}  
  6. public:  
  7.     virtual void func(int param) final { cout << "BaseClass::func. param = "  << param <<endl; }  
  8. };  
  9.   
  10. class DeriveClass : public BaseClass  
  11. {  
  12. public:  
  13.     DeriveClass(){}  
  14.     ~DeriveClass(){}  
  15. public:  
  16.     //error C3248: 'BaseClass::func': function declared as 'final' cannot be overridden by 'DeriveClass::func'  
  17.     virtual void func(int param) override { cout << "DeriveClass::func. param = "  << param <<endl; }  
  18.   
  19. };  

由註釋部分可以看出,基類的func函數使用Final進行限定後,派生類無法再重寫改函數。


5.總結

C++11新增添的 override 和 final 說明符可以使得虛函數的繼承更加明確和安全。遵循新的規則,可以增進代碼的可讀性,使用final可以更好的對派生和重寫虛函數進行限制。


轉載自:http://blog.csdn.net/fire_lord/article/details/8540592

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章