In Why is there no base class in C++?, I quoted Stroustrup on why a common Object class for all classes is problematic in c++. In that quote there is the statement:
Using a universal base class implies cost: Objects must be heap-allocated to be polymorphic;
I really didn't look twice at it, and since its on Bjarnes home page I would suppose a lot of eyes have scanned that sentence and reported any misstatements.
A commenter however pointed out that this is probably not the case, and in retrospect I can't find any good reason why this should be true. A short test case yields the expected result of VDerived::f()
.
struct VBase { virtual void f() { std::cout <<"VBase::f()\n"; } }; struct VDerived: VBase { void f() { std::cout << "VDerived::f()\n"; } }; void test(VBase& obj) { obj.f(); } int main() { VDerived obj; test(obj); }
Of course if the formal argument to test was test(VBase obj)
the case would be totally different, but that would not be a stack vs. heap argument but rather copy semantics.
Is Bjarne flat out wrong or am I missing something here?
Polymorphism is inherently good. It refers to something having many forms, referring to both objects and methods. Polymorphism allows you to code to an interface that reduces coupling, increases reusability, and makes your code easier to read.
The word polymorphism means having many forms. Typically, polymorphism occurs when there is a hierarchy of classes and they are related by inheritance. C++ polymorphism means that a call to a member function will cause a different function to be executed depending on the type of object that invokes the function.
To know whether an object is polymorphic, you can perform a simple test. If the object successfully passes multiple is-a or instanceof tests, it’s polymorphic. As described in our post about inheritance, all Java classes extend the class Object. Due to this, all objects in Java are polymorphic because they pass at least two instanceof checks.
Polymorphism is one of the core concepts of object-oriented programming (OOP) and describes situations in which something occurs in several different forms. In computer science, it describes the concept that you can access objects of different types through the same interface.
But what is polymorphism? Let’s discuss. Polymorphism is one of the core concepts of object-oriented programming (OOP) and describes situations in which something occurs in several different forms. In computer science, it describes the concept that you can access objects of different types through the same interface.
This is called static polymorphism because the compiler statically binds the method call to a specific method. Within an inheritance hierarchy, a subclass can override a method of its superclass. If you instantiate the subclass, the JVM will always call the overridden method, even if you cast the subclass to its superclass.
Looks like polymorphism to me.
Polymorphism in C++ works when you have indirection; that is, either a pointer-to-T
or a reference-to-T
. Where T
is stored is completely irrelevant.
Bjarne also makes the mistake of saying "heap-allocated" which is technically inaccurate.
(Note: this doesn't mean that a universal base class is "good"!)
I think Bjarne means that obj
, or more precisely the object it points to, can't easily be stack-based in this code:
int f(int arg) { std::unique_ptr<Base> obj; switch (arg) { case 1: obj = std::make_unique<Derived1 >(); break; case 2: obj = std::make_unique<Derived2 >(); break; default: obj = std::make_unique<DerivedDefault>(); break; } return obj->GetValue(); }
You can't have an object on the stack which changes its class, or is initially unsure what exact class it belongs to.
(Of course, to be really pedantic, one could allocate the object on the stack by using placement-new on an alloca
-allocated space. The fact that there are complicated workarounds is beside the point here, though.)
The following code also doesn't work as might be expected:
int f(int arg) { Base obj = DerivedFactory(arg); // copy (return by value) return obj.GetValue(); }
This code contains an object slicing error: The stack space for obj
is only as large as an instance of class Base
; when DerivedFactory
returns an object of a derived class which has some additional members, they will not be copied into obj
which renders obj
invalid and unusable as a derived object (and quite possibly even unusable as a base object.)
Summing up, there is a class of polymorphic behaviour that cannot be achieved with stack objects in any straightforward way.
Of course any completely constructed derived object, wherever it is stored, can act as a base object, and therefore act polymorphically. This simply follows from the is-a relationship that objects of inherited classes have with their base class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With