问题
I'm a Java programmer and recently started studying C++. I'm confused by something.
I understand that in C++, to achieve polymorphic behavior you have to use either pointers or references. For example, consider a class Shape
with an implemented method getArea()
. It has several subclasses, each overriding getArea() differently. Than consider the following function:
void printArea(Shape* shape){
cout << shape->getArea();
}
The function calls the correct getArea()
implementation, based on the concrete Shape
the pointer points to.
This works the same:
void printArea(Shape& shape){
cout << shape.getArea();
}
However, the following method does not work polymorphicaly:
void printArea(Shape shape){
cout << shape.getArea();
}
Doesn't matter what concrete kind of Shape
is passed in the function, the same getArea()
implementation is called: the default one in Shape
.
I want to understand the technical reasoning behind this. Why does polymorphism work with pointers and references, but not with normal variables? (And I suppose this is true not only for function parameters, but for anything).
Please explain the technical reasons for this behavior, to help me understand.
回答1:
The answer is copy semantics.
When you pass an object by value in C++, e.g. printArea(Shape shape)
a copy is made of the object you pass. And if you pass a derived class to this function, all that's copied is the base class Shape
. If you think about it, there's no way the compiler could do anything else.
Shape shapeCopy = circle;
shapeCopy
was declared as a Shape
, not a Circle
, so all the compiler can do is construct a copy of the Shape
part of the object.
回答2:
When void printArea(Shape shape)
is called, your object is copied into a brand new Shape
on the stack. The subclass parts are not copied. This is known as object slicing. If the base-class object is not legit (e.g. it has pure virtual functions in it), you can't even declare or call this function. That's "pass by value" semantics; a copy of the passed-in object is supplied.
When void printArea(Shape& shape)
is called, a reference to your Circle
or Rectangle
object is passed. (Specifically, a reference to the Shape
part of that object. You can't access the Circle
- or Square
-specific members without casting. But virtual functions work correctly, of course.) That's "pass by reference" semantics; a reference to the original object is passed in.
回答3:
You're talking about run-time polymorphism.
This is the idea that an object can be of a class derived from the *statically known class, so that calls to virtual member functions in the statically known class, end up in derived class implementations.
With a pointer or reference the most derived class can be different from (more specific than) the statically known class. But with a direct variable the statically known class is the most derived class. So there's no room for run-time polymorphism, except in calls that end up causing calls from base class member functions (in a base class member function the statically known type is that base class, different from the most derived class).
*) Statically known class means known to the compiler without any analysis, the declared class.
回答4:
Basically, when you pass an object by value it's copied to an object of the destination type - at that point it is an object of the destination type, so there's nothing to polymorph (is that even a word?).
To use your example, void printArea(Shape shape);
, inside the printArea()
function the parameter shape
is a Shape
object, regardless of what object was used at the call site.
来源:https://stackoverflow.com/questions/26188221/why-cant-i-do-polymorphism-with-normal-variables