2014-07-07 99 views
2

我預計這個工作:重寫在派生類中某些重載而不是其他

template <typename T> class MyBaseClass 
{ 
public: 
    MyBaseClass(); 

    virtual ~MyBaseClass(); 

    void DoSomething(const T& myClass); 
     // Implemented in .cpp file 

    virtual void DoSomething(int n, const T& myClass); 
       // Implemented in .cpp file 
}; 

class MyDerivedClass : public MyBaseClass<int> 
{ 
public: 
    virtual void DoSomething(int n, const int& myInt); 
       // Implemented in .cpp file 
}; 

...在我的代碼的其他地方:

int i; 
MyDerivedClass myClass; 
myClass.DoSomething(i); 

但是,它不支持;相反,它失敗,出現錯誤,說來編譯(在Visual C++的情況下)

error C2660: 'int::DoSomething' : function does not take 1 arguments 

...即使有明顯 DoSomething的一個版本,在基類中聲明,該確實只需要一個參數。該錯誤消失,如果我註釋掉的DoSomething的重新定義與派生類參數。

什麼微妙的C++規則有我的地方自然落下犯規,而且是有解決這個優雅的方式?

+0

對不起,我錯了我的第一個評論。 –

+1

請編輯您的代碼,'myBaseClass'需要資金首字母和'詮釋MyDerivedClass'必須'類MyDerivedClass' – TemplateRex

+0

我的猜測是它的功能查找的一些複雜性。該函數在派生中找到,而不是進一步查看;只有重載解析被嘗試(派生內)失敗(派生不聲明該簽名)。參看http://en.cppreference.com/w/cpp/language/overload_resolution –

回答

2

C++陰影中的方法全部具有相同名稱的超類方法。在你的例子

virtual void DoSomething(int n, const int& myInt); 

在派生類陰影

void DoSomething(const T& myClass); 
在基類

,與派生類型的對象工作時,因此後一種方法是不可見的。

此行爲是像Java語言編寫的完全不同,其中一個方法不會影其他方法具有相同的名稱但不同的簽名,並可能在第一次覺得有點直覺。其原因僅僅是C++的名稱查找規則:一旦在範圍中找到名稱,就不會考慮其他範圍。在你的例子中,編譯器在派生類中找到DoSomething(const T&),並停止在超類中查找更多方法。

有一個簡單的補救措施:爲了讓所有DoSomething方法可見再次,使用using指令在派生類中:

using MyBaseClass<int>::DoSomething; 

using指令使得這再次陰影可見的方法,通過拉他們進入派生類的範圍。現在,名稱查找將在派生類的範圍內找到正確的DoSomething(int, const int&)方法。

+1

或者直接調用陰影方法:'myClass。MyBaseClass :: DoSomething(i);' – SomeWittyUsername

+0

@icepack:您的建議適用於此場景,但通常不是您想要的,因爲它會禁用虛擬方法的「vtable」查找。所以,如果'DoSomething(int)'是虛擬的,你的調用總是調用'MyBaseClass :: DoSomething(int)',而不是在潛在的子類中重載'DoSomething(int)'方法! – gexicide

+0

當然,這就是爲什麼我明確地加上前綴:)我認爲如果明確的前綴將允許多態行爲將會相當混亂 – SomeWittyUsername

相關問題