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

时间:2015-02-24 13:20:15

标签: c++ multiple-inheritance c++98 covariant

我的代码与此相同:

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

我相信我可以在 B类 D 中写一些东西,以防止 A :: foo 继承,但我不会&#39;不知道是什么。也许有一些功能可以在C ++中重命名冲突名称?

PS&GT;我不能使用C ++ 11,只能使用旧的C ++ 98。

3 个答案:

答案 0 :(得分:1)

<强> TL; DR

在课程foo中覆盖D。由于不相关的fooX返回类型,Y方法无法协变。两者都不能因为不同的返回类型而重载,但签名相同。


<强> 解释

让我们将代码清理为具有相同问题的较小代码段:

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>
};

好的,上课D继承了fooA中的两个C<Y>方法。这两个导入的方法可以共存,因为它们来自不同的父级,可以通过限定的调用来调用它们,例如D d; d.A::foo();

但是在这种情况下,当您尝试覆盖课程foo中的D时,问题会出现在图片中:

/*virtual*/ Y * foo() {};

在课程D中,有一个方法X * foo()继承自A,您将覆盖方法Y * foo()。这些不能协变,because Y is not derived from X。另一方面,此foo不能超载另一个Because return type is not part of function signature

阅读clang的错误信息很好:

  

错误:返回类型的虚函数'foo'与。不协调   它覆盖的函数的返回类型('Y *'不是从'X'派生的   *')

virtual Y * foo() {};

<强> 解决方案

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

答案 1 :(得分:0)

您说您不需要在foo中声明的C<X>方法并在A中实施,但由于您的班级D也是 - { {1}}和A客户端可能依赖于此方法可用,并返回C<X>。 C ++不支持删除继承的方法AFAIK,因为这会违反Liskov替换原则。

如果您在此处删除或隐藏X,则C<X>::fooD或{{1}的实例无法使用A的实例} 是期待。所以我担心这里没有解决这个问题的好办法。如果您只是尝试重用B中的C<X>A中的实现,那么在这种情况下您可能应该考虑使用合成而不是继承。

答案 2 :(得分:-1)

您可以将private inheritance用于A.

class B : private A {};

通常,返回类型不能是重载的唯一区别。