Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
601 views
in Technique[技术] by (71.8m points)

c++ - "Invalid covariant return type" errors in nested classes with methods returning template-based objects

The following C++ code gives me these errors when compiled:

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()’

I do not want to change the line virtual Q<B> test() {} to virtual Q<A> test() {} although it removes the compilation errors. Is there another way to solve this problem?

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() {}
};
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Q<B> and Q<A> are unrelated classes. Imagine you are a client of B calling test(): what do you assign the result to, if you do not know what type it is going to have?

The fact that both Q<A> and Q<B> are instances of the same class template does not change the fact that they are two completely unrelated classes, possibly with a completely different layout (due to template specialization).

This would not be any different from doing:

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

The client calling test() on a pointer to X would expect the result to be a string, but "Whoops!", the object pointed to by that pointer is of type Y, and the return type of Y::test() is int. What should happen? A run-time crash?

Y y;
X* p = &y;
std::string s = p->test(); // D'OH!

C++ is a statically typed language, meaning that type checking is performed at compile-time. In this case, the message from the compiler is there to tell you that the derived class does not adhere to the interface of the class it derives from.

If you are wondering what "invalid covariant return type" means, and in particular the word "covariant", that's easily explained.

Suppose you have a base class B with a virtual function foo() that returns an X*:

struct B
{
    virtual X* foo();
};

And suppose that you have a class D derived from B that overrides foo() by returning an Y*, where Y is a class derived from X:

struct D : B
{
    virtual Y* foo();
};

Is this a problem? Well, the right answer comes from answering this slightly better question: "Would that be a problem for a client calling foo() that expects an X* to be returned?"

And the answer to that question is obviously "No", since Y is a derived class of X, so you can return a pointer to Y instead of a pointer to 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

This is an example of a covariant return type. In your example, the return type of C::test() is not covariant with respect to the return type of B::test().


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

56.8k users

...