[英]Why is the base class method called if the derived class overrides the method?
考慮以下程序:
class Base {
public:
virtual void foo() const {
cout << "Base::foo()" << endl;
}
};
class Derived : public Base {
public:
virtual void foo() {
cout << "Derived::foo()" << endl;
}
};
void func(Base& obj) {
obj.foo();
}
void main() {
Derived d;
func(d); // Base::foo() is printed
}
如果我從Base
class foo
方法中刪除const
,則調用Derived::foo()
。 我似乎無法理解這種行為。
1)這種行為的原因是什么?
2)這是在編譯時還是運行時決定的?
謝謝
在派生的 class 中,function 簽名是這樣的:
virtual void foo(); //Derived::foo
其中沒有提到const
。 它是一個非常量成員 function,而Base::foo
是一個const成員 function。 它們是兩個不同的函數,因為const
是 function 簽名的一部分。
virtual void foo() const; //Base::foo
派生的 class 不會覆蓋此 function,而是添加另一個 function。
所以修復是這樣的:
class Derived : public Base {
public:
virtual void foo() const {
cout << "Derived::foo()" << endl;
}
};
因為const
是 function 簽名的一部分。 所以當你打算覆蓋 base 的 foo 時必須提到它。
@davka 問道:
那么為什么選擇常量版本而不是非常量版本? 是否有任何規則,或者它恰好是第一個選擇?
這是因為obj
的static類型是Base
,而 function 名稱是基於 ZA81259CEF8E959C624ZDF1D456E5D3297Z45B66A8CFDE8913AC1 的類型解析的 Base
甚至沒有非常量版本。 所以不存在被選中或拒絕的問題。 它一開始在Base
中不存在。
void func(Base& obj) {
obj.foo(); //calls Base::foo
}
但是,如果將上面的代碼更改為以下內容:
void func(Derived & obj) {
obj.foo(); //calls Derived:foo
}
現在將選擇非常量版本,因為Base::foo
隱藏在Derived
class 中。
由於Derived::foo
隱藏了Base::foo
,因此您不能使用Derived
的實例調用后者。
現在,讓我們取消隱藏Base::foo
並做更多的實驗。
class Derived : public Base {
public:
using Base::foo; //<----------------this unhides Base::foo
virtual void foo() {
cout << "Derived::foo()" << endl;
}
};
現在在 Derived 中,兩個函數(const 和 non-const 版本)都可用,未隱藏。 現在有幾個有趣的問題。
既然現在 Derived 已經隱藏了這兩個函數,那么下面的每個 function 會調用哪個 function?
void f(Derived& obj) {
obj.foo(); //Which function? Base::foo or Derived::foo?
}
void g(const Derived & obj) {
obj.foo(); //Which function? Base::foo or Derived::foo?
}
第一個將調用Derived::foo
,它是非常量版本,第二個將調用Base::foo
,它是 const 版本。 原因很簡單,使用 const object,只能調用const函數,但使用非 const 對象,兩者都可以調用,但如果可用,則選擇非 const 版本。
見在線演示: http://www.ideone.com/955aY
您沒有覆蓋該方法,因為Derived::foo
並不完全相同。
要覆蓋方法,基本版本和覆蓋版本必須相同,包括const
-ness。
在 C++ 中,您可以擁有兩個具有相同名稱和相同參數的函數,其中唯一的區別是一個是const
,一個不是。
這個想法是你有時想要不同的行為。 例如,訪問 function function 可能具有不同的返回類型:
class MyClass
{
public:
virtual Xxx * GetXxx();
virtual Xxx const * GetXxx() const;
// ....
}
您可以單獨覆蓋這些函數。
在您的情況下,當您從非常量 object 調用foo
時,您調用了 function 的非常量變體。 由於您已經覆蓋了 const-variant,所以基礎 class 中的那個就是被調用的那個。
您正在做的事情稱為“重載”。 正如@SLaks 指出的那樣,在覆蓋時,簽名需要相同。
const
是簽名的一部分。 void foo() const
是與void foo()
不同的 function 。 你根本沒有壓倒一切。 這就是為什么。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.