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() {}
};
Q<B>
andQ<A>
are unrelated classes. Imagine you are a client ofB
callingtest()
: 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>
andQ<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:
The client calling
test()
on a pointer toX
would expect the result to be astring
, but "Whoops!", the object pointed to by that pointer is of typeY
, and the return type ofY::test()
isint
. What should happen? A run-time crash?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 functionfoo()
that returns anX*
:And suppose that you have a class
D
derived fromB
that overridesfoo()
by returning anY*
, whereY
is a class derived fromX
: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 anX*
to be returned?"And the answer to that question is obviously "No", since
Y
is a derived class ofX
, so you can return a pointer toY
instead of a pointer toX
: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 ofB::test()
.The function with the signature
B::test(void)
returns an object of typeQ<A>
, whileC::test(void)
(which is the same signature, so you're overwriting the function) returnsQ<B>
. I think that is impossible.As far as I know it is impossible to overload a function by return type and overwrites of parent functions need to stick to the same return type.
From the Standard §10.3/7
You cannot do that. Overrides of virtual functions cannot change the prototype of the function, except very specific cases, such as the covariant return types.
Covariant return would be valid if you were to return in the virtual override a subclass of the type returned in the virtual base. But your
Q<A>
andQ<B>
are unrelated by inheritance. The fact thatB
is a subclass ofA
does not make any difference here.