我正在試驗這段代碼
class Base
{
public:
virtual void foo(int) {
// void foo(int) {
cout << "int" << endl;
}
};
class Derived : public Base
{
public:
void foo(double) {
cout << "double" << endl;
}
};
int main()
{
Base* p = new Derived;
p->foo(2.1);
Derived d;
d.foo(2); // why isn't this double?
return 0;
}
它也可以在此處的在線編輯器中使用https://onlinegdb.com/s8NwhfG_Yy
我越來越
int
double
我不明白為什么 d.foo(2) 呼叫雙版本。由于 Derived 繼承了 int 方法并有自己的 double 方法,所以多型性不會要求 2 與父項匹配嗎?謝謝。
uj5u.com熱心網友回復:
呼叫虛方法時的多型性與符號和多載決議正交。前者發生在運行時,其余發生在編譯時。
object->foo() 總是在編譯時決議符號- 具有多載operator()或方法的成員變數。virtual只會延遲選擇方法的“主體”。簽名總是固定的,當然包括回傳值。否則型別系統會崩潰。這就是不能有虛函式模板的原因之一。
您實際遇到的是名稱隱藏和多載決議。
對于Base* p; p->foo(2.1),可能的候選符號串列僅為Base::foo(int)。編譯器無法知道p指向Derived(通常),因為選擇必須在編譯時完成。由于int可隱式轉換為double,因此foo(int)被選中。因為該方法是虛擬的,如果Derived要提供它自己的foo(int) override,它會被呼叫而不是Base::foo(int)在運行時呼叫。
對于Derived*d; d->foo(2),編譯器首先查找符號foo在Derived。由于存在foo(double)有效為foo(2),因此選擇了它。如果沒有有效的候選者,只有這樣編譯器才會查看基類。如果有Derived::foo(int),可能是虛擬的,編譯器會選擇它,因為它是一個更好的匹配。
您可以通過寫入禁用名稱隱藏
class Derived: public Base{
using Base::foo;
};
它將所有Base::foo方法注入Derived作用域。在此之后,Base::foo(int)(現在真的Derived::foo(int))被選為更好的匹配。
uj5u.com熱心網友回復:
閱讀過載解決方案。答案在詳細資訊中:
如果任何候選函式是成員函式(靜態或非靜態),但不是建構式,則將其視為具有額外引數(隱式物件引數),該引數表示為其呼叫它們并出現在第一個之前的物件的實際引數。
方法void foo(int)和之間的選擇void foo(double)就像在函式void foo(Base, int)和void foo(Derived, double). 呼叫時的第二個函式d.foo(2)排名更高。
如果添加using Base::foo;的Derived,該決議將三種功能之間進行void foo(Base, int),void foo(Derived, int)并且void foo(Derived, double),和int將被列印。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/331741.html
上一篇:在一個模板定義中使用兩種型別
