问题
s->duplicate()
returns an object of type Box*
, but I'm getting an error initializing it with Box*
. It looks like it's being converted back to Shape*
. What is the point of having covariant return types if it's converted back to the base class pointer?:
struct Shape
{
virtual Shape* duplicate()
{
return new Shape;
}
};
struct Box : Shape
{
virtual Box* duplicate()
{
return new Box;
}
};
int main()
{
Shape* s = new Box;
Box* b = s->duplicate();
}
Error:
main.cpp:22:12: error: cannot initialize a variable of type 'Box *' with an rvalue of type 'Shape *'
Box* b = s->duplicate();
^ ~~~~~~~~~~~~~~
1 error generated.
回答1:
Although Box::duplicate
is being invoked at runtime (via virtual dispatch), and although Box::duplicate
does override Shape::duplicate
(covariantly), and although Box::duplicate
does return a Box*
, you'll still get a Shape*
pointer because you are calling duplicate()
through a Shape*
pointer, and Shape*
is the return type of Shape::duplicate()
, and the compiler only sees you calling Shape::duplicate
, not Box::duplicate
.
C++ is not able to dynamically select types, so this is the best it can do. Your Box*
is being automatically converted to a Shape*
on the way out of Box::duplicate
. As Barry said, "it still has to compile at compile time, and at compile time all we know is that it returns a Shape*
".
Then, to make it into a Box*
again, you need to explicitly cast it (using static_cast
or dynamic_cast
) because no implicit down-conversion exists.
[C++11: 10.3/7]:
The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions. [..]
[C++11: 10.3/8]:
If the return type ofD::f
differs from the return type ofB::f
, the class type in the return type ofD::f
shall be complete at the point of declaration ofD::f
or shall be the class typeD
. When the overriding function is called as the final overrider of the overridden function, its result is converted to the type returned by the (statically chosen) overridden function (5.2.2). [..]
In the standard text, a pertinent example follows.
回答2:
The point isn't to do this:
Box* b = s->duplicate();
That obviously can't work since Shape::duplicate()
returns a Shape*
. The point, rather, is to accept a Box*
if you're calling duplicate()
on a Box
directly:
Box* old = new Box;
Box* b = old->duplicate(); // OK! We know it's a Box
来源:https://stackoverflow.com/questions/28132869/covariant-return-type-and-type-conversion