It is a well-known idiom to define a virtual destructor for the classes with virtual functions. If we don't define a virtual destructor, then the base class destructor will be invoked when you are deleting the object through the base class pointer even if the object is an instance of derived class.
Although this sounds intuitive, it is non-trivial to the C++ compiler
implementation. Some extra care should be paid if the programmer didn't
specify the desturctor. For example, in the following code, the base class
A
has a virtual destructor and the derived class B
does not
define any destructor. What will happen when after running delete a
?
class A {
public:
virtual ~A() { }
};
class B : public A {
};
int main() {
A *a = new B();
delete a;
}
If your compiler is following the Itanium C++ ABI, then the compiler will
synthesize two functions _ZN1BD0Ev()
and _ZN1BD2Ev()
.
- The
_ZN1BD2Ev()
is the synthesized destructor which will destruct the instance members of classB
and will in turn call the_ZN1AD2Ev()
to destruct the members of classA
. - The
_ZN1BD0Ev()
will invoke_ZN1BD2Ev()
to destruct the object and deallocate the memory withoperator delete (void *)
(or namely_ZdlPv()
.)
Back to the example, when the delete a
is executed, the underlying code
sequence will get the second function pointer (index 1) from the virtual method
table and pass the object address to the corresponding function, which is
_ZN1BD0Ev()
in this case.
In fact, if you define the destructor in the derived class, then your destructor
will be part of the _ZN1BD2Ev()
. You can check the behavior with the
following code:
extern "C" void test() throw ();
class A {
public:
virtual ~A() { }
};
class B : public A {
public:
virtual ~B() {
test();
}
};
int main() {
A *a = new B();
delete a;
}
p.s. You can generate the LLVM assembly with clang++ -S -emit-llvm
which is more readable.