1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
When an object ceases to exist the object's i(destructor) is called. Now
consider the following code fragment (cf. section ref(VehicleSystem)):
verb( Vehicle *vp = new Land{ 1000, 120 };
delete vp; // object destroyed)
Here tt(delete) is applied to a base class pointer. As the base class
defines the available interface tt(delete vp) calls tt(~Vehicle) and tt(~Land)
remains out of sight. Assuming that tt(Land) allocates memory a
i(memory leak) results. Freeing memory is not the only action destructors can
perform. In general they may perform any action that's necessary when an
object ceases to exist. But here none of the actions defined by tt(~Land) are
performed. Bad news....
In bf(C++) this problem is solved by
hi(destructor: virtual)hi(virtual destructor) em(virtual destructors). A
destructor can be declared tt(virtual). When a base class destructor is
declared virtual then the destructor of the actual class pointed to by a base
class pointer tt(bp) is going to be called when tt(delete bp) is
executed. Thus, late binding is realized for destructors even though the
destructors of derived classes have unique names. Example:
verb( class Vehicle
{
public:
virtual ~Vehicle(); // all derived class destructors are
// now virtual as well.
};)
By declaring a virtual destructor, the above tt(delete) operation
(tt(delete vp)) correctly calls tt(Land)'s destructor, rather than
tt(Vehicle)'s destructor.
Once a destructor is called it performs as usual, whether or not it
is a virtual destructor. So, tt(~Land) first executes its own statements
and then calls tt(~Vehicle). Thus, the above tt(delete vp) statement
uses late binding to call tt(~Vehicle) and from this point on the object
destruction proceeds as usual.
Destructors should always be defined tt(virtual) in classes designed as a
base class from which other classes are going to be derived. Often those
destructors themselves have no tasks to perform. In these cases the virtual
hi(empty destructor) hi(destructor: empty)
destructor is given an empty body. For example, the definition of
tt(Vehicle::~Vehicle()) may be as simple as:
verb( Vehicle::~Vehicle()
{})
Resist the temptation to define virtual destructors (even empty
destructors)
hi(destructor: inline) i(inline) as this complicates class
maintenance. Section ref(VTABLE) discusses the reason behind this
i(rule of thumb).
|