问题
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::fdiffers from the return type ofB::f, the class type in the return type ofD::fshall be complete at the point of declaration ofD::for 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