2014-07-07 58 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

相关问题