C++11顯式虛函數重載:override與final

場景

在傳統C++中,經常容易發現意外重載虛函數的事情:

struct Base {
    virtual void foo();
};

struct SubClass: Base {
    void foo();
};

有下列三種場景:

  • SubClass::foo可能是程序員加入的一個和基類虛函數恰好同名的成員函數,卻被編譯器當作重載虛函數
  • SubClass::foo可能是程序員想重載虛函數,但是因爲形參列表不同導致編譯器認爲這是一個新定義的成員函數
  • 當基類的虛函數Base::foo被刪除後,SubClass::foo就不再重載該虛函數而搖身一變成爲一個普通的成員函數

override

一旦類中的某個函數被聲明爲虛函數,那麼在所有的派生類中它都是虛函數。一個派生類的函數如果覆蓋了某個繼承而來的虛函數,那麼它的形參類型必須與基類函數完全一致。

派生類中如果定義了一個函數與基類中虛函數的名字相同但是形參列表不同,編譯器會認爲新定義的函數與基類中原有的函數是相互獨立的。這會帶來一個問題:如果我們本來希望派生類可以覆蓋掉基類中的虛函數,但是一不小心把形參列表寫錯了,這可能與我們的本意不符。

C++11新標準提供了override關鍵字來顯式地告知虛擬器進行重載,編譯器將檢查基類是否存在這樣的虛函數,否則將無法通過編譯。這樣的好處是使得程序員的意圖更加清晰(覆蓋基類中的虛函數),如果我們使用override關鍵字標記了某個函數但是該函數沒有覆蓋已有的虛函數,此時編譯器會報錯。

struct Base {
    virtual void foo(int);
};

struct SubClass: Base {
    virtual void foo(int) override;  // 合法
    virtual void foo(float) override;  // 非法, 父類無此虛函數
};

final

我們可以把類中的某個函數指定爲final,之後任何嘗試覆蓋該函數的操作都會引發錯誤,用於防止類被繼續繼承或者終止虛函數繼續重載。

struct Base {
    virtual void foo() final;
};

struct SubClass1 final: Base {  
};  // 合法

struct SubClass2: SubClass1 {
};  // 非法, SubClass1已final

struct SubClass3: Base {
    void foo();  // 非法, foo已final
};

Reference

[1] C++ Primer

[2] 現代C++教程

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