2012-06-03 43 views
7

有人可以解釋爲什麼下面的代碼的結果是「class B :: 1」?代碼執行派生類方法,但從基類方法獲取默認參數

爲什麼派生類的虛方法使用基類的默認參數而不是他自己的?對我來說這很奇怪。提前致謝!

代碼:

#include <iostream> 

using namespace std; 

class A 
{ 
public: 
    virtual void func(int a = 1) 
    { 
     cout << "class A::" << a; 
    } 
}; 

class B : public A 
{ 
public: 
    virtual void func(int a = 2) 
    { 
     cout << "class B::" << a; 
    } 
}; 

int main() 
{ 
    A * a = new B; 
    a->func(); 

    return 0; 
} 

回答

6

因爲默認參數根據靜態類型this(即,變量本身的類型,如A& a;中的A&)。

修改你的例子稍微:

#include <iostream> 

class A 
{ 
public: 
    virtual void func(int a = 1) 
    { 
     std::cout << "class A::" << a << "\n"; 
    } 
}; 

class B : public A 
{ 
public: 
    virtual void func(int a = 2) 
    { 
     std::cout << "class B::" << a << "\n"; 
    } 
}; 

void func(A& a) { a.func(); } 

int main() 
{ 
    B b; 
    func(b); 
    b.func(); 

    return 0; 
} 

我們遵守以下的輸出:

class B::1 
class B::2 

在行動,在ideone

出於此原因,不建議虛擬功能更改默認值。不幸的是,我不知道任何編譯器會警告這個構造。


的技術解釋是,有處理默認參數的方法有兩種:

  • 創建一個新的功能,作爲蹦牀:void A::func() { func(1); }
  • 加載在呼叫缺少的參數網站a.func() =>a.func(/*magic*/1)

如果是前者(並假設A::func瓦特同樣也宣稱爲virtual),那麼它會像你期望的那樣工作。然而,後一種形式是當選的,或者是因爲virtual當時沒有預見到問題,或者因爲面臨好處(如果有的話)被認爲是無關緊要的。

5

因爲缺省值被編譯期間被取代,並從聲明取,而真正的函數被稱爲(A :: FUNC或B :: FUNC)在運行時被確定。

+0

感謝您的快速回答! – Aremyst

5

由於C++中的多態性在運行時生效,而默認參數的替換在編譯時生效。在編譯時,編譯器不知道(也不應該知道)指針a指向的對象的動態類型。因此,默認參數爲a所知的唯一類型,在您的示例中爲A *。 (這偶然也是缺省參數在接口/頭文件中給出的原因,而不是在實現/定義中給出的。編譯器永遠不會在實現的機器代碼中插入默認參數,但僅在調用者的機器碼中插入。 ,默認參數是調用者的屬性;調用者不知道 - 也不應該知道 - 對象的動態類型。)

+0

你的回答非常清楚,謝謝! – Aremyst