Why can't I do polymorphism with normal variables?

牧云@^-^@ 提交于 2019-12-17 14:50:32

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!