具有多重继承的 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() {};
^
我相信我可以在 class B 或 D 中写一些东西来防止 A:: foo 从继承,但我不知道是什么。也许有一些功能可以在 C++ 中重命名冲突名称?
PS> 我不会使用 C++11,只能使用旧的 C++98。
你可以用 private inheritance 作为 A.
class B : private A {};
一般来说,return类型不能是重载的唯一区别。
TL;DR
覆盖 class D
中的 foo
。由于不相关的 X
和 Y
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 D
从 A
和 C<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
的实例将无法在 A
、B
或 C<X>
是预期的。所以这里恐怕没有很好的解决这个问题的方法。如果您只是想在 D
中重用 A
或 B
的实现,那么在这种情况下您可能应该考虑组合而不是继承。
我有与此等效的代码:
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() {};
^
我相信我可以在 class B 或 D 中写一些东西来防止 A:: foo 从继承,但我不知道是什么。也许有一些功能可以在 C++ 中重命名冲突名称?
PS> 我不会使用 C++11,只能使用旧的 C++98。
你可以用 private inheritance 作为 A.
class B : private A {};
一般来说,return类型不能是重载的唯一区别。
TL;DR
覆盖 class D
中的 foo
。由于不相关的 X
和 Y
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 D
从 A
和 C<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
的实例将无法在 A
、B
或 C<X>
是预期的。所以这里恐怕没有很好的解决这个问题的方法。如果您只是想在 D
中重用 A
或 B
的实现,那么在这种情况下您可能应该考虑组合而不是继承。