結合超載和重寫的結果考慮下面的代碼C++中奇怪的行爲
class X{
public:
virtual void foo(X x){ }
virtual void foo(int index){ }
};
class Y : public X{
public:
void foo(int index){ }
};
int main(){
Y y;
y.foo(X()); //Error, see below
}
X
類已超載虛擬foo
方法。一個版本需要X
,另一個版本需要int
。現在類Y
繼承自X
並覆蓋方法foo(int)
。方法foo(X)
不會被覆蓋,它應該保持不變。
然而,在main
方法創建Y
類型的對象和呼叫foo(X)
時,編譯器會抱怨以下:
In function ‘int main()’:
error: no matching function for call to ‘Y::foo(X)’
note: candidate is:
note: virtual void Y::foo(int)
note: no known conversion for argument 1 from ‘X’ to ‘int’
因此,唯一候選者是重寫foo(int)
方法。看來另一種方法已經消失了。如果我刪除覆蓋版本,即聲明Y
爲public Y : public X{};
,那麼一切正常。爲什麼會發生?
這是爲什麼?這意味着,默認情況下,派生類違反了Liskov的原則,這對C++來說是一個非常糟糕的設計決定。 – gexicide
@gexicide:實際上它並沒有違反LSP,因爲當你通過指針或對基類的引用訪問派生類*時,所有基類的方法仍然可以照常使用。 –
@gexicide:這個語言決定的原因是不隱藏基類函數可能會導致意外的行爲。想象一下,代替'X',另一個基類超載需要一個'double'。類'Y'的用戶可能會調用'y.foo(2.5)',期望調用'Y :: foo(int)';相反,將調用'X :: foo(double)';用戶不希望存在的功能。 – Gorpik