當心虛函數重載(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很容易知道它是虛函數, 需要父類子類同時更改.