2011-01-27 61 views
1

今天,我發現了以下令人不安的曖昧情況在我們的代碼庫:我如何知道哪個函數會被調用?

class Base { 
public: 
    virtual void Irrelevant_Function(void) = 0; 

protected: 
    C_Container * Get_Container(void); 
}; 

class A : public Base, public Not_Important { 
public: 
    inline C_Container * Get_Container(void); 
}; 

class B : public Base, protected SomethingElse { 
public: 
    C_Container * Get_Container(void); 
}; 

很多事情都調用Get_Container方法,但並不總是調用正確的 - 注意,所有這些功能都是虛擬的。

我需要重新命名方法Get_Base_Container,Get_A_Container等以消除歧義。 C++使用什麼規則來確定它應該調用哪個版本的函數?我想從本來應該被調用的「已知狀態」開始,然後找出那裏的錯誤。

例如,如果我有一個指向Base的指針並調用Get_Container,我認爲它只會調用該函數的基本版本。如果我有指向A的指針呢?那麼指向B的指針呢?那堆上的A或B怎麼樣?

謝謝。

+0

如果您已經在基類中使用`= 0;`來編寫它,它將不會編譯。 `= 0`只能用於純虛擬方法。 – wheaties 2011-01-27 23:16:48

回答

5

這取決於你如何調用函數。如果您通過A *A &A撥打電話,則您將撥打A::Get_Container()。如果您通過Base *Base &(即使他們指向/參考A)撥打電話,則您將撥打Base::Get_Container()

3

只要不存在虛擬繼承,這很容易。如果您直接使用對象,則會調用該對象的方法;如果您正在使用指針或引用,則它是確定方法的指針或引用的類型,並且指向的對象的類型無關緊要。

1

首先根據對象的靜態類型查找方法。如果它是非虛擬的,那麼你就完成了:這就是所謂的方法。動態類型是虛擬方法,dynamic_cast和typeid使用的,並且是對象的「實際」類型。靜態類型是靜態類型系統使用的。

A a;      // Static type and dynamic type are identical. 
Base &a_base = a;   // Static type is Base; dynamic type is A. 

a.Get_Contaienr();   // Calls A::Get_Container. 
a_base.Get_Container(); // Calls Base::Get_Container. 

B *pb = new B();   // Static type and dynamic type of *pb (the pointed-to 
          // object) are identical. 
Base *pb_base = pb;  // Static type is Base; dynamic type is B. 

pb->Get_Container();  // Calls B::Get_Container. 
pb_base->Get_Container(); // Calls Base::Get_Container. 

我上面假設受保護的Base :: Get_Container方法是可訪問的,否則那些將是編譯錯誤。

1

這裏需要注意幾點:

名稱查找發生在單個作用域中;例如。在靜態類型爲'B'的對象上調用該方法時,編譯器會認爲'B'的接口確定是否存在有效的匹配。如果沒有,它只會看基地的接口來找到一個匹配。這就是爲什麼從編譯器的角度來看,沒有任何不明之處,它可以解決這個問題。如果你的真實代碼有重載等,這可能是一個問題。其次,經常忘記'受保護的'關鍵字適用於類而不是對象級。例如:

class Base { 
protected: 
    C_Container * Get_Container(void); 
}; 

class B : public Base{ 
public: 
    C_Container * Get_Container(void) 
    { 
     B b; 
     // Call the 'protected' base class method on another object. 
     return b.Base::Get_Container(); 
    } 
}; 
相關問題