问题
Ah, SO came back just in time.
I am getting a strange error:
'B::blah': overriding virtual function return type differs and is not covariant from 'A::blah'
Here is the code causing the problem:
class A {
public:
class Inner { };
virtual Inner blah() = 0;
};
class B : public A {
public:
class Inner2 : public Inner { };
Inner2 blah() {
return Inner2();
}
};
I looked up the error, and according to a page I found on the Microsoft website, one of the ways types can be covariant is if:
the class in the return type of B::f is the same class as the class in the return type of D::f or, is an unambiguous direct or indirect base class of the class in the return type of D::f and is accessible in D
Is that not the case with Inner
and Inner2
? I am using Microsoft Visual C++ 2010 if it matters.
OK, so thanks to John I learned that only pointers and references can be covariant. Why is that? A Derived can be cast to a Base, so why don't virtual functions with return types that are derived from the same thing just cast the return type to the one of the base class? In my example, it seems like it would make sense to have (A*(new B))->blah()
return a Inner
that is really an Inner2
that has been cast up.
回答1:
Only pointers and references can be covariant.
回答2:
If what you request would be allowed it would mean that a call to blah() via the base class must do a conversion from Inner2 to Inner... a cast is not possible since the caller is responsible for managing the returned object (since it is not returned by pointer/reference but by value) and will reserve space for it on the stack. So it can only handle Inner not Inner2 or whatever ancestor class.
So you then have an instance of Inner, not Inner2... So you don't get any advantage...
回答3:
Imagine that your example worked.
Consider the following code:
A *a = some_function();
A::Inner inner = a->blah();
If the dynamic type of a
is B*, then a->blah()
calls a::B->blah()
, and returns a B::Inner
. This is then silently sliced into an instance of A::Inner
. In general, this (and any type of slicing) is not what you want. I find this to be a good restriction.
回答4:
Why is that?
Simply because the ISO C++ standard committee ruled it that way!
There is no fundamental reason. It could be done differently, at the cost of a tiny additional compiler complexity.
回答5:
objects declared on the runtime stack must be known to the compiler at compile time:
void f(const A & a) {
Inner inr = a.blah( );
}
inr must be of both static and dynamic type "Inner" (not "Inner2") to be allocated off the stack -- so if blah returned an Inner2 it would be used to construct an Inner and it's "2ness" would be lost (or sliced as K Dragon mentions).
回答6:
The blah
method have to return A::Inner in all cases -- if you think of the reason it is quite simple. A instance of B could easily be case to the base class A. Now if anybody calls blah on A (the base class which object should it return? Inner2 or Inner?
来源:https://stackoverflow.com/questions/6969020/overriding-virtual-function-return-type-differs-and-is-not-covariant