【问题标题】:Overriding some overloads in a derived class but not others覆盖派生类中的一些重载,但不覆盖其他重载
【发布时间】:2014-07-07 09:44:57
【问题描述】:

我希望这会起作用:

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++ 规则,有没有一种优雅的方法可以解决这个问题?

【问题讨论】:

  • 抱歉,我的第一条评论有误。
  • 请编辑您的代码,myBaseClass 需要大写首字母,int MyDerivedClass 需要是class MyDerivedClass
  • 我猜这是函数查找的一些复杂性。该函数在派生中找到,不再进一步查看;只有在重载解析(在派生内)尝试失败(派生不声明该签名)。参照。 en.cppreference.com/w/cpp/language/overload_resolution
  • 顺便说一句,template &lt;typename T&gt; void MyBaseClass&lt;T&gt;::DoSomething(const T&amp; myClass) 的实现应该放在标题中...
  • @TemplateRex,你说得对;我已经这样做了。

标签: c++ inheritance overloading virtual


【解决方案1】:

C++ 中的方法隐藏了超类中具有相同名称的所有 方法。在你的例子中

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

在派生类的阴影中

void DoSomething(const T& myClass);

在基类中,因此在使用派生类型的对象时后一种方法不可见。

这种行为与 Java 等其他语言完全不同,Java 中的方法不会影响具有相同名称但不同签名的其他方法,并且一开始可能会觉得有点反直觉。其原因仅仅是 C++ 的名称查找规则:一旦在范围内找到名称,就不会考虑进一步的范围。在您的示例中,编译器在您的派生类中找到 DoSomething(const T&amp;) 并停止在超类中寻找更多方法。

有一个简单的补救措施:要使所有 DoSomething 方法再次可见,请在派生类中使用 using 指令:

using MyBaseClass<int>::DoSomething;

using 指令通过将被遮蔽的方法拉入派生类的范围,使它们再次可见。现在,名称查找将在派生类的范围内找到正确的DoSomething(int, const int&amp;) 方法。

【讨论】:

  • 或者直接调用shaded方法:myClass.MyBaseClass::DoSomething(i);
  • @icepack:您的建议适用于这种情况,但通常不是您想要的,因为它将禁用vtable 对虚拟方法的查找。因此,如果DoSomething(int) 是虚拟的,您的调用将始终调用MyBaseClass::DoSomething(int),而不是潜在子类中的覆盖DoSomething(int) 方法!
  • 当然,这就是我显式添加前缀的原因 :) 我认为如果显式前缀允许多态行为会很混乱
  • @icepack:但这不是你通常想要的。在这里,问题只是方法阴影。您可以通过从完全正交的被调用方法中移除多态性来解决它。
  • 谢谢;只需在声明我的重载之前在行上添加“使用”指令就可以了。正如您所说,这是违反直觉且令人恼火的,但至少解决方法是无痛的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-05
  • 2022-01-10
  • 2010-10-24
  • 1970-01-01
相关资源
最近更新 更多