以下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() {}
};

最佳答案

Q<B>Q<A>是不相关的类。假设您是B的客户,调用test():如果不知道结果的类型,您将结果分配给什么?
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>
};

客户端在指向test()的指针上调用X会期望结果为string,但是“Whoops!”,该指针所指向的对象的类型为Y,而Y::test()的返回类型为int。应该怎么办?运行时崩溃?
Y y;
X* p = &y;
std::string s = p->test(); // D'OH!

C++是一种静态类型的语言,这意味着类型检查是在编译时执行的。在这种情况下,来自编译器的消息会告诉您派生类不遵循其派生类的接口(interface)。

如果您想知道“无效的协变量返回类型”是什么意思,尤其是单词“covariant”,这很容易解释。

假设您有一个带有虚拟函数B的基类foo(),该函数返回了X*:
struct B
{
    virtual X* foo();
};

并假设您有一个从D派生的B类,它通过返回foo()覆盖了Y*,其中Y是从X派生的类:
struct D : B
{
    virtual Y* foo();
};

这有问题吗?好吧,正确的答案来自回答这个稍微好一点的问题:“对于调用foo()并希望返回X*的客户端来说,这会是一个问题吗?”

这个问题的答案显然是“No”,因为YX的派生类,因此您可以返回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

这是协变返回类型的示例。在您的示例中,C::test()的返回类型与B::test()的返回类型不是协变的。

09-10 06:36
查看更多