天天看點

當心虛函數重載(overloaded-virtual)

當心虛函數重載(overloaded-virtual)

(轉載請注明來源于金慶的專欄)

為網遊萬王之王3(KOK3)伺服器添加新功能的時候,

發現某個類成員函數應該是const函數, 因為我的const函數要調用該函數,

順手就加上了const.

再順便看到該類有好多個明顯是getter函數, 是以都加上了const.

編譯沒錯就送出了.

結果沒多久測試就發現了新版本的一個錯誤, 表現在其他功能上,

但由同僚糾錯後發現是我添加const的後果.

原來添加const的成員函數中, 有一個是virtual函數, 加了const後與子類的函數原型就不符了.

子類的函數成為父類虛函數的一個重載, 使virtual失效, 多态性無法表現出來.

解決方法就是子類的相應虛函數中也添加const.

教訓: 更改虛函數原型時, 必須同時更改父類和子類.

gcc中有個-Woverloaded-virtual警告選項, 會報告這種虛函數重載.

我在Makefile中打開了-Woverloaded-virtual, 再次編譯時就産生了許多警告.

大多數警告是正确的函數重載, 但還是發現了一個與我相同的錯誤,

這次是函數參數const有差別, 我發給相關人員處理了.

因為開了-Werror, 所有警告都會造成編譯失敗,

是以我們不能在Makefile中加入-Woverloaded-virtual警告選項.

代碼示例:

class A

{

    virtual void f() {};

};

class B : public A

{

    virtual void f() const {};

};

int main()

{

    return 0;

}

$ g++ main.cpp -Woverloaded-virtual

main.cpp:3: warning: `virtual void A::f()' was hidden

main.cpp:8: warning:   by `virtual void B::f() const'

Google的代碼規範中要求所有子類的虛函數中都加上virtual, 是很有道理的.

雖然隻要與父類虛函數簽名相同, 加不加virtual都是虛函數,

但是以後更改函數簽名時, 看到virtual很容易知道它是虛函數, 需要父類子類同時更改.