下面的C++代码在编译时会给出以下错误:
covariant.cpp:32:22: error: invalid covariant return type for ‘virtual Q<B> C::test()’
covariant.cpp:22:22: error: overriding ‘virtual Q<A> B::test()’我不想将行virtual Q<B> test() {}更改为virtual Q<A> test() {},尽管它删除了编译错误。有没有别的办法来解决这个问题?
template <class T>
class Q
{
public:
Q() {}
virtual ~Q() {}
};
class A
{
public:
A() {}
virtual ~A() {}
};
class B
{
public:
B() {}
virtual ~B() {}
virtual Q<A> test() = 0;
};
class C : public B
{
public:
C() {}
virtual ~C() {}
virtual Q<B> test() {}
};发布于 2013-06-23 03:20:30
Q<B>和Q<A>是不相关的类。假设您是调用test()的B的客户端:如果您不知道结果将具有什么类型,那么您将结果分配给什么?
虽然Q<A>和Q<B>都是同一个类模板的实例,但这并不能改变它们是两个完全不相关的类的事实,它们可能具有完全不同的布局(由于模板专门化)。
这与执行以下操作没有什么不同:
struct X
{
virtual std::string test() = 0;
};
struct Y : X
{
virtual int test() { return 42; } // ERROR! std::string and int are
// unrelated, just as Q<A> and Q<B>
};客户端在指向X的指针上调用test()时,期望结果是string,但是“哇!”,该指针所指向的对象是Y类型,而Y::test()的返回类型是int。应该发生什么?运行时崩溃?
Y y;
X* p = &y;
std::string s = p->test(); // D'OH!C++是一种静态类型语言,这意味着类型检查是在编译时执行的。在这种情况下,来自编译器的消息告诉您派生类不符合派生类的接口。
如果你想知道“无效的协变返回类型”是什么意思,特别是“协变”这个词,这很容易解释。
假设您有一个带有虚拟函数foo()的基类B,该函数返回一个X*
struct B
{
virtual X* foo();
};假设您有一个从B派生的类D,它通过返回一个Y*覆盖了foo(),其中Y是从X派生的类
struct D : B
{
virtual Y* foo();
};这是一个问题吗?好的,正确的答案来自于回答这个稍微好一点的问题:“对于调用foo()并期望返回X*的客户端来说,这会有问题吗?”
这个问题的答案显然是“否”,因为Y是X的派生类,所以您可以返回指向Y的指针,而不是指向X的指针
D d;
B* b = &d;
X* p = b->foo(); // Returns an Y*, but that's OK, because a pointer to Y can be
// assigned to a pointer to X这是一个协变返回类型的示例。在您的示例中,相对于B::test()的返回类型,C::test()的返回类型不是协变的。
发布于 2013-06-23 03:19:32
签名为B::test(void)的函数返回Q<A>类型的对象,而C::test(void) (签名相同,因此您将覆盖该函数)返回Q<B>。我认为这是不可能的。
据我所知,通过返回类型重载函数是不可能的,父函数的重写需要坚持相同的返回类型。
来自标准§10.3/7
重写函数的返回类型应与重写函数的返回类型相同或与函数的类协变。如果函数D::f覆盖函数B::f,则函数的返回类型在满足以下条件时是协变的:
的右值引用,
发布于 2013-06-23 03:21:04
你不能这么做。虚函数的重写不能更改函数的原型,除非是非常特殊的情况,例如协变返回类型。
如果要在虚拟覆盖中返回在虚拟基中返回的类型的子类,则协变返回将是有效的。但是您的Q<A>和Q<B>通过继承是不相关的。B是A的子类这一事实在这里没有任何区别。
https://stackoverflow.com/questions/17254381
复制相似问题