1.簡介
C++爲我們提供了繼承和虛函數的重寫特性。 在派生類中,重寫虛函數不強制要求使用 virtual 關鍵字,並且C++並沒有要求強制檢查虛函數的重寫是否真正覆蓋了基類的虛函數,因爲在派生類中,也可以增添新的虛函數,以供下一級的派生類重寫。由於檢查的不夠嚴謹,就有可能產生錯誤。
2.有可能產生的錯誤
最常見的錯誤就是派生類想要重寫基類的虛函數,但是由於參數類型的不同,導致結果和預期不同,例如:
- #include"stdafx.h"
- #include<iostream>
- using namespace std;
- class BaseClass
- {
- public:
- BaseClass(){}
- ~BaseClass(){}
- public:
- virtual void func(int param) { cout << "BaseClass::func. param = " << param <<endl; }
- virtual void func2() const { cout<< "BaseClass::func2."<<endl;}
- };
- class DeriveClass : public BaseClass
- {
- public:
- DeriveClass(){}
- ~DeriveClass(){}
- public:
- virtual void func(float param) { cout << "DeriveClass::func. param = " << param <<endl; }
- virtual void func2() { cout<< "DeriveClass::func2."<<endl;}
- };
- int main()
- {
- BaseClass* pBase = new BaseClass();
- pBase->func(1);
- pBase->func2();
- cout<<endl;
- DeriveClass* pDerive = new DeriveClass();
- pDerive->func(4);
- pDerive->func2();
- cout<<endl;
- BaseClass* pTest = new DeriveClass();
- pTest->func(5);
- pTest->func2();
- cout<<endl;
- system("pause");
- return 0;
- }
輸出結果爲
對於函數func,派生類和基類的參數類型不同,雖然函數的返回值和函數名相同,並使用了virtual進行虛函數的聲明,但實際上派生類並沒有重寫基類的虛函數,而是定義了自己的虛函數。使用const 進行限定也是一樣,在基類中func2 爲 const 函數,而派生類沒有 const 進行限定,因此,派生類也並沒有重寫基類的虛函數。 pTest 的輸出結果和我們原本預期的並不相同,其調用的是基類的虛函數。由上圖輸出結果可以看出。
3. override
爲了避免上述問題的發生,C++11增添了override, override並不是一個關鍵字,而是一個用於標記虛函數重寫的標識符,使用override 標記的類成員函數表示我們希望其重寫基類相對應的虛函數。如果沒有重寫,編譯器會報錯。例如:
- class BaseClass
- {
- public:
- BaseClass(){}
- ~BaseClass(){}
- public:
- virtual void func(int param) { cout << "BaseClass::func. param = " << param <<endl; }
- virtual void func2() const { cout<< "BaseClass::func2."<<endl;}
- };
- class DeriveClass : public BaseClass
- {
- public:
- DeriveClass(){}
- ~DeriveClass(){}
- public:
- //error C3668: 'DeriveClass::func' : method with override specifier 'override' did not override any base class methods
- virtual void func(float param) override { cout << "DeriveClass::func. param = " << param <<endl; }
- //error C3668: 'DeriveClass::func2' : method with override specifier 'override' did not override any base class methods
- virtual void func2() override { cout<< "DeriveClass::func2."<<endl;}
- };
對DeriveClass 的兩個成員函數使用了 override ,編譯器知道我們期望重寫基類的虛函數,但是由於基類並沒有相匹配的虛函數,因此編譯出錯,出錯信息如上述註釋部分所示。
4.final
在一些情況下,我們並不希望某個成員函數再被任何派生類所繼承,在java語言中,有final來進行限定,C++11也提供了 final (同 override一樣不是關鍵字,只是特殊的標識符)。通過使用final對虛函數的限定,任何子類不能重寫該函數,例如:
- class BaseClass
- {
- public:
- BaseClass(){}
- ~BaseClass(){}
- public:
- virtual void func(int param) final { cout << "BaseClass::func. param = " << param <<endl; }
- };
- class DeriveClass : public BaseClass
- {
- public:
- DeriveClass(){}
- ~DeriveClass(){}
- public:
- //error C3248: 'BaseClass::func': function declared as 'final' cannot be overridden by 'DeriveClass::func'
- virtual void func(int param) override { cout << "DeriveClass::func. param = " << param <<endl; }
- };
由註釋部分可以看出,基類的func函數使用Final進行限定後,派生類無法再重寫改函數。
5.總結
C++11新增添的 override 和 final 說明符可以使得虛函數的繼承更加明確和安全。遵循新的規則,可以增進代碼的可讀性,使用final可以更好的對派生和重寫虛函數進行限制。