The reason why you cannot use polymorphism with values, but links and pointers

I found below the C ++ Polymorphism without pointers message which explains that the C ++ polymorphism function should use a pointer or reference types.

I looked at some additional resources, they all say the same thing, but the reason.

Are there technical difficulties to support polymorphism with values ​​or is it possible, but C ++ decided not to provide this ability?

+7
c ++ polymorphism
source share
4 answers

The problem with processing values ​​is polymorphically reduced to the slicing problem: since derived objects can use more memory than their base class, declaring a value in automatic storage (i.e., on the stack) leads to memory allocation only for the base, and not for the derived object. Therefore, parts of an object that belong to a derived class can be cut. That is why C ++ developers made an informed decision to redirect virtual member functions in the base class implementation that cannot touch data elements of a derived class.

+9
source share

The difficulty arises because the objects that you call objects are allocated in automatic memory (on the stack), and the size must be known at compile time.

The size of the pointers is known at compile time no matter what they point to, and the links are executed as pointers under the hood, so don't worry.

Consider the objects:

BaseObject obj = ObjectFactory::createDerived(); 

How much memory should be allocated for obj if createDerived() conditionally returns derived objects? To overcome this, the returned object is chopped and "converted * to a BaseObject whose size is known.

All this is connected with the mentality of "pay for what you use."

+4
source share

The short answer is that the standard indicates it. But are there any insurmountable technical obstacles to resolving it?

C ++ data structures are of known size. Polymorphism usually requires data structures to vary in size. In general, you cannot store another type (larger) in a smaller type of storage, so storing a child class with additional variables (or other reasons to be larger) in storage for the parent class is usually not possible.

Now we can get around this. We can create a buffer of a larger size than is required to store the parent class, and build child classes in this buffer: but in this case, the specified instance will be exposed via links, and you will finish the class carefully.

This is similar to the method known as “small object optimization” used by boost::any , boost::variant and many std::string implementations, where we store (by value) objects in a buffer inside the class and manage their lifetime manually.

There is also a problem where the Derived pointers for an instance can have different values ​​than the Base pointers for an instance: the values ​​of object instances in C ++ are supposed to exist where the instance store starts with most implementations.

Thus, theoretically, C ++ can allow polymorphic instances if we restrict it to derived classes that can be stored in the same memory space with the same “pointer to” value for Derived and Base , but this is an extremely narrow cornerstone case and can reduce the kinds of optimizations and assumptions that compilers could make about the values ​​of class instances in almost every case! (At the moment, the compiler may assume that instances of the values ​​of class C have virtual methods that are not overridden elsewhere, as an example). This is a non-trivial cost for an extremely minor advantage.

What else, we can use the C ++ language to emulate this corner case using existing language functions (placing new ones, links and manual destruction) if we really need it without imposing this cost higher.

+1
source share

It is not immediately clear what you mean by "polymorphism with values." In C ++, when you have an object of type A , it always behaves like an object of type A This is quite normal and logical to expect. I do not see how this can behave differently. Thus, it is unclear what kind of “abilities” someone decided not to provide, which you are talking about.

Polymorphism in C ++ means one thing: calls to virtual functions made using an expression with a polymorphic type are resolved according to the dynamic type of this expression (in contrast to the static type for non-virtual functions). That is all that is needed.

Polymorphism in C ++ always works in accordance with the rule above. It works this way through pointers. This works through links. It works this way through immediate objects ("values", as you called them). So, it’s not entirely correct to say that polymorphism in C ++ only works with pointers and links. It also works with "values." They all follow the same rule as above.

However, for a direct object ("value"), its dynamic type always matches its static type. So, although polymorphism works for immediate meanings, it does not show anything truly “polymorphic”. The behavior of an immediate object with polymorphism is the same as without polymorphism. So, the polymorphism of an immediate object is a degenerate, trivial polymorphism. It exists only conceptually. This, again, is completely logical: an object of type A should behave like an object of type A How else can he behave?

To observe actual non-degenerate polymorphism, you need an expression whose static type differs from its dynamic type. Nontrivial polymorphism is observed when an expression of a static type A behaves (with respect to calls to virtual functions) as an object of a different type B For this, an expression of static type A must really refer to an object of type B This is only possible with pointers or links. The only way to make this difference between a static and a dynamic type of expression is to use pointers or references.

In other words, it is not true to say that polymorphism in C ++ only works through pointers or links. It’s right to say that with pointers or links, polymorphism becomes observable and non-trivial.

+1
source share

All Articles