Reputation: 910
I have some specific questions on virtual destructors and vtable.
Suppose I have the following code:
class Base
{
public:
virtual ~Base();
};
class Child : public Base
{
public:
~Child();
};
Questions:
Upvotes: 4
Views: 5361
Reputation: 175
Every class with virtual methods (declared/inherited) has its own virtual table(vtable). When a virtual method (any, not just the destructor) is declared virtual, all overrides of that method in derived classes are automatically virtual. The compiler also adds _vptr at the beginning of any such classes having virtual methods. This _vptr will be filled when the class's object is created and will point to the vtable of that class. A virtual destructor is treated the same way as any other virtual function. In your example since ~Base is virtual, ~Child will be virtual as well.
Suppose if you do:
Child *child = new (class Child);
delete(child);
Here, child->_vptr would be pointing to Child's vtable. So during delete, ~Child will be called first & followed by ~Base (in the reverse order of construction).
Alternately if you do,
Base *base = new (class Child);
delete(base);
Here, base->_vptr would be pointing to Child's vtable. So during delete, ~Child will be called first & followed by ~Base from the vtable.
In gdb, we can verify this _vptr by running this command,
"info vtbl base" or "print *base"
Upvotes: 1
Reputation: 727027
The explanation below assumes that virtual dispatch implementation used by the compiler is based on virtual tables.
Each class with virtual methods (declared or inherited) has its own virtual table. If a subclass overrides a virtual member function in the base, a pointer to the overriding function is placed in the class's vtable; otherwise, a pointer to base class implementation is kept in place.
Adding the first virtual function increases the size of the class instance by the size of vtable pointer. Virtual functions after the first one do not add to the size of the instance.
Since ~Base
is virtual, the ~Child
is virtual as well, even though virtual
keyword is omitted. In case of an override, virtual
keyword is optional.
Upvotes: 6
Reputation: 67822
Creating an instance of type Child via the new operator then delete ... will the Base destructor be called?
Not in the original question code, because you don't have Child
inheriting from Base
.
Assuming that's a mistake, and we fix it, then ~Base
would be called when you destroy a Child
even if it weren't virtual, just because the base-class sub-object is destroyed as part of the normal destruction sequence.
The reason for virtual destructors is so you can delete a Child
via a Base *
and still have ~Child
invoked correctly.
Eg, with:
struct Base { ~Base(); };
struct Child: Base { ~Child(); };
struct VBase { virtual ~VBase(); };
struct VChild: VBase { ~VChild(); };
this works for both hierarchies:
template <typename Derived>
void test_static() {
Derived d;
}
test_static<Child>(); // ~Child then ~Base invoked when d is destroyed
test_static<VChild>(); // ~VChild then ~VBase invoked when d is destroyed
but this only works with a virtual destructor:
template <typename Derived, typename Base>
void test_dynamic() {
std::unique_ptr<Base> p(new Derived);
}
test_dynamic<Child, Base>; // only ~Base invoked when p destroyed
test_dynamic<VChild,VBase>; // ~VChild then ~VBase invoked as before.
As for the vtable questions, it's an implementation detail whether one exists, and if so where it is, and you don't need to worry about it.
Upvotes: 2