具有多重继承的 C++ 协变 return 类型错误

C++ covariant return type error with multiple inheritance

我有与此等效的代码:

class X {};
class Y {};

template< typename T>
  class C {
  public:
      virtual  T * foo() = 0;
  };

class A : public C< X> {
public:
    X * foo() {};
};

class B : public A {};

class D : public B, public C< Y> {
public:
    Y * foo() {}; //this is the only one method I need here. Not A::foo!
};

我遇到了这个错误:

error:   invalid covariant return type for 'virtual Y* D::foo()'
 Y * foo() {};
     ^

和:

error:   overriding 'virtual X* A::foo()'
 X * foo() {};
     ^

http://ideone.com/PAgTdX

我相信我可以在 class BD 中写一些东西来防止 A:: foo 从继承,但我不知道是什么。也许有一些功能可以在 C++ 中重命名冲突名称?

PS> 我不会使用 C++11,只能使用旧的 C++98。

你可以用 private inheritance 作为 A.

class B : private A {};

一般来说,return类型不能是重载的唯一区别。

TL;DR

覆盖 class D 中的 foo。由于不相关的 XY return 类型,foo 方法不能协变。两者都不能,由于 return 类型不同但签名相同,因此不能重载。


解释

让我们将代码清理成具有相同问题的更小片段:

class X {};
class Y {};

template<typename T>
class C {
public:
    virtual T * foo() = 0;
};

class A : public C<X> {
public:
    // Your code:
    // X * foo() {}; <---- This method is irrelevant to the problem

    // virtual X * foo() {};
    // ^^^^^^^^^^^^^^^^^^^^^
    // This method declared via inheritance and template
    // and implicitly exists in this class, (look at keyword `virtual`)
};

class D : public A, public C<Y> {
public:
    /*virtual*/ Y * foo() {}; // `virtual` comes from C<X>
};

嗯,class DAC<Y> 继承了两个 foo 方法。这两个引入的方法可以共存,因为它们来自不同的父类,并且可以通过合格的调用来调用它们,例如D d; d.A::foo();.

但在这种情况下,当您尝试在 class 中覆盖 foo D:

时,问题就出现了
/*virtual*/ Y * foo() {};

在 class D 中,有一个签名为 X * foo() 的方法继承自 A,而您正在重写方法 Y * foo()。这些不能协变,because Y is not derived from X. On the other hand, this foo can not overload another one, Because return type is not part of function signature.

看看clang的报错信息就好了:

error: return type of virtual function 'foo' is not covariant with the return type of the function it overrides ('Y *' is not derived from 'X *')

virtual Y * foo() {};

解决方案

最好的解决方案是简化您的设计并摆脱这些复杂的继承、模板化和同名方法!!

您是说您不需要在 C<X> 中声明并在 A 中实现的 foo 方法,但是由于您的 class D 也是一个 A 和一个 C<X>,客户端可能依赖于此方法是否可用,并返回一个 X。 C++ 不支持删除继承的方法 AFAIK,这是有充分理由的,因为这会违反 Liskov 替换原则。

如果您确实在此处删除或隐藏了 C<X>::foo,那么 D 的实例将无法在 ABC<X> 是预期的。所以这里恐怕没有很好的解决这个问题的方法。如果您只是想在 D 中重用 AB 的实现,那么在这种情况下您可能应该考虑组合而不是继承。