Why can't I polymorphism with normal variables?

I am a Java programmer and recently started to learn C ++. I'm embarrassed by something.

I understand that in C ++ you must use either pointers or references to achieve polymorphic behavior. For example, consider the Shape class with the getArea() method implemented. It has several subclasses, each of which differs from getArea () in different ways. Then consider the following function:

 void printArea(Shape* shape){ cout << shape->getArea(); } 

The function calls the correct getArea() implementation, based on the specific Shape pointed to by the pointer.

This works the same way:

 void printArea(Shape& shape){ cout << shape.getArea(); } 

However, the following method does not work polymorphically:

 void printArea(Shape shape){ cout << shape.getArea(); } 

It doesn’t matter what concrete form of Shape is passed into the function, the same getArea() implementation is getArea() : by default in Shape .

I want to understand the technical argument. Why does polymorphism work with pointers and references, but not with ordinary variables? (And I believe that this is true not only for function parameters, but also for something).

Please explain the technical reasons for this behavior to help me understand.

+5
source share
4 answers

The answer is copy semantics.

When you pass an object by value in C ++, for example. printArea(Shape shape) executes a copy of the object you are passing. And if you pass a derived class to this function, everything that is copied is the base class of Shape . If you think about it, the compiler cannot do anything.

 Shape shapeCopy = circle; 

shapeCopy was declared as Shape , not Circle , so all the compiler can do is build a copy of the Shape part of the object.

+4
source

When void printArea(Shape shape) is called, your object is copied to the new Shape on the stack. Parts of the subclass are not copied. This is called object splitting . If the object of the base class is not legal (for example, it has pure virtual functions in it), you cannot even declare or call this function. This is the semantics of "pass by value"; a copy of the transferred object is provided.

When void printArea(Shape& shape) is called, a reference to your Circle or Rectangle object is passed. (In particular, a link to the Shape part of this object. You cannot access the Circle - or Square elements without casting. But virtual functions work correctly, of course.) This "pass by reference" semantics; the link to the original object is passed.

+1
source

You are talking about polymorphism at runtime.

This is the idea that an object can be a class derived from a static class * so that calls to virtual member functions in a statically-known class end with implementations of the derived class.

With a pointer or reference, the most derived class may differ from the (more specific) statically known class. But with a direct variable, a statically known class is the most derived class. Thus, there is no place for run-time polymorphism, with the exception of calls that ultimately cause calls from member functions of the base class (in a member function of a base class, a statically known type is a base class different from the derived class itself).


* ) A statically known class, known to the compiler without any analysis, a declared class.
+1
source

Basically, when you pass an object by value, it is copied to an object of the target type - at this moment it is an object of the target type, so there is nothing polymorphic (is that even a word?).

To use your example void printArea(Shape shape); , inside the printArea() function, the shape parameter is a shape object, regardless of which object was used on the call site.

0
source

Source: https://habr.com/ru/post/1203979/


All Articles