struct B1 final { };
struct D1 : B1 { }; // 錯誤!不能從 final 類繼承!
上面的代碼是錯誤的,因為 D1 試圖繼承 B1,而 B1 則聲明為 final。很像 Java,不是嗎?當然!還有另外的用法:struct B2
{
virtual void f() final {} // final 函數(shù)
};
struct D2 : B2
{
virtual void f() {} // 錯誤!
};
這段代碼又會出錯,因為D2::f重寫了B2::f,但是B2::f卻被聲明為 final 的!
我總覺得 C++中虛函數(shù)的設計很差勁,因為時至今日仍然沒有一個強制的機制來標識虛函數(shù)會在派生類里被改寫。vitual關鍵字是可選的,這使得閱讀代碼變得很費勁。因為可能需要追溯到繼承體系的源頭才能確定某個方法是否是虛函數(shù)。為了增加可讀性,我總是在派生類里也寫上virtual關鍵字,并且也鼓勵大家都這么做。即使這樣,仍然會產(chǎn)生一些微妙的錯誤。
下面再看另外一段代碼:
struct B3
{
virtual void f() {}
};
struct D3 : B3
{
void f() {}
};
開發(fā) D3 的程序員真的想重寫B(tài)3::f函數(shù)嗎?還是說,他只是不小心寫了個與父類同名的函數(shù),卻在不經(jīng)意間導致了覆蓋?為了避免這種錯誤,C++ 11 引入了override關鍵字(多么像 C# ?。。?。于是,我們會發(fā)現(xiàn),下面的一段代碼是會出錯的:struct B4
{
virtual void g(int) {}
};
struct D4 : B4
{
virtual void g(int) override {} // OK
virtual void g(double) override {} // Error
};
多虧了override關鍵字,我們可以讓編譯器幫我們檢測到這個很難發(fā)現(xiàn)的程序錯誤。這段代碼的錯誤在于,override關鍵字表明,g(double)雖然想要進行override的操作,但實際父類并沒有這么個函數(shù)。值得注意的是,這些并不是一些語法糖,而是能確確實實地避免很多程序錯誤,并且暗示編譯器可以作出一些優(yōu)化。調(diào)用標記了final的virtual函數(shù),例如上面的B2::f,GNU C++ 前端會識別出,這個函數(shù)不能被覆蓋,因此會將其從類的虛表中刪除。而標記為final的類,例如上面的 B1,編譯器則根本不會生成虛表。這樣的代碼顯然更有效率。
https://www.devbean.net/2012/05/cpp11-override-final/