Following this question, I'm wondering why a struct\class in C++ has to have a virtual method in order to be polymorphic.
Forcing a virtual destructor makes sense, but if there's no destructor at all, why is it mandatory to have a virtual method?
Following this question, I'm wondering why a struct\class in C++ has to have a virtual method in order to be polymorphic.
Forcing a virtual destructor makes sense, but if there's no destructor at all, why is it mandatory to have a virtual method?
Because the type of a polymorphic object in C++ is, basically, determined from the pointer to its vtable, which is the table of virtual functions. The vtable is, however, only created if there's at least one virtual method. Why? Because in C++, you never get what you didn't explicitly ask for. They call it "you don't have to pay for something you don't need". Don't need polymorphism? You just saved a vtable.
In C++, runtime polymorphism is achieved through virtual functions.
So? –
Centrepiece virtual
functions and vtable
are two different things. –
Tamera vtable
and vptr
concept to implement this, but that isn't mandated by the C++ Standard. –
Tamera virtual
and those without. Thus to be pedantic replace vtable in the answer with compiler-defined-virtual-identity-system. ;) –
Ethyne Forcing a virtual destructor makes sense
Exactly. To destruct a virtual class manually (via delete
) through its base class you need a virtual destructor. (Now, as I’ve been reminded in the comments, this isn’t usually needed: rather than use manual memory management, one would rely on modern smart pointers which also work correctly with non-virtual destructors.)
So any class which acts as a polymorphic base class usually needs either a virtual destructor or virtual functions anyway.
And since having runtime polymorphism adds an overhead (the class needs to store an additional pointer to its virtual method table), the default is not to add it, unless necessary anyway: C++’ design philosophy is “you only pay for what you need”. Making every class have a virtual method table would run afoul of this principle.
shared_ptr
or unique_ptr
(if available), then the object can be correctly deleted non-polymorphically. It is only needed if its owner stores it in a container of raw base-class pointers, or if ownership is transferred using auto_ptr
or a raw pointer, neither of which I would regard as typical use cases. On the other hand, I tend to avoid inheritance, so my use cases may differ from others'. –
Ambroid Because it is defined as such in the standard.
From 10.3/1 [class.virtual]
Virtual functions support dynamic binding and object-oriented programming. A class that declares or inherits a virtual function is called a polymorphic class.
It makes sense that if you use inheritance, then you have at least one virtual method. If you don't have any virtual method, then you could use composition instead.
polymorphism is to allow your subclasses to override the default behaviour of base class functions, so unless you have virtual methods in your base class, you can't override methods in base.
dynamic_cast
from A*, then A needs a useless virtual function just to make it polymorphic (usually the destructor). That's pretty rare, though, that you'd want to store in a container using a base class pointer, but don't want to make virtual calls. –
Riobard virtual ~A() {}
, but YMMV ;-p. Then again, I very rarely use dynamic polymorphism in C++, so I'm exactly the person that you're paying for. –
Riobard I'm wondering why does a struct\class in C++ has to have a virtual method in order to be polymorphic?
Because that is what polymorphic class means.
In C++, runtime polymorphism is achieved through virtual functions. A base class declares some virtual functions which the many derived classes implement, and the clients use pointers (or references) of static type of base class, and can make them point to objects of derived classes (often different derived classes), and then later on, call the implementation of derived classes through the base pointers. That is how runtime polymorphism is achieved. And since the central role is played by the functions being virtual
, which enables runtime polymorphism, that is why classes having virtual functions is called polymorphic class.
Without any virtual method, there is no need to maintain a virtual pointer (abbreviated as vptr) for every object of the class. The virtual pointer is a mechanism for resolving virtual method calls at runtime; depending on the object's class, it might point to different virtual method tables (abbreviated as vtable) that contain the actual adresses of virtual methods.
So by checking to what vtable does the vptr point to, compiler can determine object's class, for example in dynamic_cast
. Object without the vptr cannot have its type determined this way and is not polymorphic.
A C++ design philosophy is that "you don't pay for what you don't use". You might already know that a virtual
function incur some overhead as a class has to maintain a pointer to its implementation. In fact, an object contains a reference to a table of function pointers called the vtable.
Consider the following example:
class Base
{
public:
virtual f() { /* do something */ }
};
class Derived : public Base
{
public:
virtual f() { /* do something */ }
};
Base* a = new Derived;
a->f(); // calls Derived::f()
Note that the variable a
points to a Derived
object. As f()
is declared virtual
the vtable of a
will contain a pointer to Derived::f()
and that implementation is executed. If f()
is not virtual
, the vtable will be empty. So Base::f()
is executed as the type of a
is Base
.
A destructor behaves just like other member functions. If the destructor is not virtual
, only the destructor in the Base
class will be called. This might lead to memory/resource leaks if the Derived
class implements RAII. If a class is intended to be sub-classed, its destructor should be virtual
.
In some languages like Java all methods are virtual. So even objects that are not intended to be polymorphic will consume memory for maintaining the function pointers. In other words, you are forced to pay for what you don't use.
Classes only need virtual methods in order to be dynamically polymorphic - for the reasons described by others. You can still have static polymorphism through templates, though.
© 2022 - 2024 — McMap. All rights reserved.