9

I found below post C++ polymorphism without pointers that explains to have polymorphism feature C++ must use pointer or reference types.

I looked into some further resources all of them says the same but the reason .

Is there any technical difficulty to support polymorphism with values or it is possible but C++ have decided to not to provide that ability ?

Community
  • 1
  • 1
nish1013
  • 3,658
  • 8
  • 33
  • 46
  • This phenomenon is called "slicing" and is related to the fact that pointers can point to anything, and that references are easily (and often) implemented using pointers. –  Jul 08 '13 at 19:23
  • You can use unions as a little polymorphism aproach with value types. – Manu343726 Jul 08 '13 at 20:25

4 Answers4

12

The problem with treating values polymorphically boils down to the object slicing issue: since derived objects could use more memory than their base class, declaring a value in the automatic storage (i.e. on the stack) leads to allocating memory only for the base, not for the derived object. Therefore, parts of the object that belong to the derived class may be sliced off. That is why C++ designers made a conscious decision to re-route virtual member-functions to the implementations in the base class, which cannot touch the data members of the derived class.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
4

The difficulty comes from the fact that what you call objects are allocated in automatic memory (on the stack) and the size must be known at compile-time.

Size of pointers are known at compile-time regardless of what they point to, and references are implemented as pointers under the hood, so no worries there.

Consider objects though:

BaseObject obj = ObjectFactory::createDerived();

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

This all stems from the "pay for what you use" mentality.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • Many thanks for this reply, could you please provide a reference for this answer to get further info? – nish1013 Jul 08 '13 at 19:36
  • @nish1013 Search for `automatic allocation` and you will get further information. C++ is nothing like Java or C# internally, especially if it's about automatic allocation. Which is a big advantage regarding of speed, but also quite a loss regarding of (virtual) inheritance. But fortunately you have choices in C++ covering all. – Tim Jul 08 '13 at 20:54
1

The short answer is because the standard specifies it. But are there any insurmountable technical barriers to allowing it?

C++ data structures have known size. Polymorphism typically requires that the data structures can vary in size. In general, you cannot store a different (larger) type within the storage of a smaller type, so storing a child class with extra variables (or other reasons to be larger) within storage for a parent class is not generally possible.

Now, we can get around this. We can create a buffer larger than what is required to store the parent class, and construct child classes within that buffer: but in this case, exposure to said instance will be via references, and you will carefully wrap the class.

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

There is also an issue where Derived pointers to an instance can have different values than Base pointers to an instance: value instances of objects in C++ are presumed to exist where the storage for the instance starts by most implementations.

So in theory, C++ could allow polymorphic instances if we restricted it to derived classes that could be stored in the same memory footprint, with the same "pointer to" value for both Derived and Base, but this would be an extremely narrow corner case, and could reduce the kinds of optimizations and assumptions compilers could make about value instances of a class in nearly every case! (Right now, the compiler can assume that value instances of a class C have virtual methods that are not overridden elsewhere, as an example) That is a non trivial cost for an extremely marginal benefit.

What more, we are capable of using the C++ language to emulate this corner case using existing language features (placement new, references, and manual destruction) if we really need it, without imposing that above cost.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1

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 as an object of type A. This is perfectly normal and logical thing to expect. I don't see how it can possible behave in any other way. So, it is not clear what "ability" that someone decided "not to provide" you are talking about.

Polymorphism in C++ means one thing: virtual function calls made through an expression with polymorphic type are resolved in accordance with the dynamic type of that expression (as opposed to static type for non-virtual functions). That's all there is to it.

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

However, for an immediate object (a "value") its dynamic type is always the same as it static type. So, even though polymorphism works for immediate values, it does not demonstrate anything truly "polymorphic". The behavior of an immediate object with polymorphism is the same as it would be without polymorphism. So, polymorphism of an immediate object is degenerate, trivial polymorphism. It exists only conceptually. This is, again, perfectly logical: an object of type A should behave as an object of type A. How else can it behave?

In order to observe the actual non-degenerate polymorphism, one needs an expression whose static type is different from its dynamic type. Non-trivial polymorphism is observed when an expression of static type A behaves (with regard to virtual function calls) as an object of different type B. For this an expression of static type A must actually refer to an object of type B. This is only possible with pointers or references. The only way to create that difference between static and dynamic type of an expression is through using pointers or references.

In other words, its not correct to say that polymorphism in C++ only works through pointers or references. It is correct to say is that with pointers or references polymorphism becomes observable and non-trivial.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765