Cla07: declare virtual destructor for a polymorphism base class
Declare destructors virtual inpolymorphic base classes
Create a TimeKeeper base class and create a derived class for different timing methods:
Class TimeKeeper {
Public:
TimeKeeper ();
Virtual ~ TimeKeeper ();
...
};
Class AtomicClock: public TimeKeeper {...}; // Atomic Clock
Class WaterClock: public TimeKeeper {...}; // water clock
Class WristWatch: public TimeKeeper {...}; // watch
TimeKeeper * getTimeKeeper ();
// Returns a pointer pointing to the Dynamic Allocation object of a TimeKeeper derived class.
TimeKeeper * ptk = getTimeKeeper (); // obtain a dynamic allocation object from the TimeKeeper Inheritance System
... // Use it
Delete ptk; // release it to avoid resource leakage
Many customers simply want to get time and do not care about how to calculate details, so a factoryfunction (factory function) -- returns a base class pointer to a newly created derived class object. -- this function can be used to return a pointer to a timing object. Consistent with the practice of factory functions, the objects returned by getTimeKeeper are stored on the stack. Therefore, to avoid Memory leakage and other resources, it is important to delete each returned object properly.
C ++ rules: When a derived class object is deleted by using a pointer to a base class of the non-virtual destructor, the derived part of the object is not destroyed. If getTimeKeeper returns a pointer to the AtomicClock object, the AtomicClock part of the object (that is, the data member declared in the AtomicClock class) is likely not parsed, the destructor of AtomicClock will not run either. However, the basic class (that is, the TimeKeeper part) may have been destructed, which leads to a strange partial destruction of objects, resulting in resource leakage.
It is easy to eliminate this problem: Give the base class a virtual destructor. Therefore, when deleting a derived class object, the entire object will be destructed, including the components of the derived class.
Basic classes similar to TimeKeeper generally contain virtual functions other than destructor, because the purpose of virtual functions is to allow customization of derived classes. For example, TimeKeeper can have a virtual function getCurrentTime, which has different implementations in different Derived classes. Any class with a virtual function is almost sure that there should also be a virtual destructor.
If a class does not contain a virtual function, this generally indicates that it is not intended to be used as a base class. When a class is not intended as a base class, it is usually a bad idea to make its destructor virtual. Consider a point class that represents a two-dimensional space:
Class Point {// a 2D point
Public:
Point (int xCoord, int yCoord );
~ Point ();
Private:
Int x, y;
};
If an int occupies 32 bits, a Point object is suitable for the 64-bit cache. In addition, such a Point object can be passed as a 64-bit value to functions written in other languages, such as C or FORTRAN. When the Point destructor is virtual, the object must carry additional information to determine which virtual function the object should call at runtime. This information is usually pointed out by a pointer called vptr ("virtual table pointer"). vptr points to a function pointer array called vtbl ("virtual table; each class with virtual functions has an associated vtbl. When a virtual function is called on an object, the actually called function is determined by the following steps: Find the vtbl to which the object vptr points, and then find the appropriate function pointer in vtbl.
If the Point class contains a virtual function, vptr will be added to the Point, which will increase the object size by 50-100%! The Point object is no longer suitable for 64-bit registers. In addition, Point objects do not have the same structure in C ++ and other languages (such as C), because the counterparts in other languages do not have vptr. As a result, Points is no longer allowed to pass in functions written in other languages or from them, and has no portability.
Declaring all destructor as virtual for no reason is the same as never declaring them as virtual. In fact, many people have summarized this rule: When and only when a class contains at least one virtual function, a virtual destructor is declared in the class.
· The polymorphism base class should declare virtual destructor. If a class has any virtual function, it should have a virtual destructor.
Even if there is no virtual function, it may be entangled in the non-virtual destructor. For example, the standard string type does not contain virtual functions, but Programmers sometimes use it as a base class:
Class SpecialString: public std: string {
... // Bad idea! Std: string has a non-virtual destructor.
};
If a pointer pointing to SpecialString is transformed into a pointer pointing to string in the program, then deleting the string pointer will cause memory leakage and the behavior is unclear:
SpecialString * pss = newSpecialString ("Impending Doom ");
Std: string * ps;
...
Ps = pss; // SpecialString * => std: string *
...
Delete ps;/* not defined! In reality, * ps SpecialString resources will leak because SpecialString destructor are not called. */
Do not attempt to inherit standard containers (such as vector, list, set, tr1: unordered_map) or any other class with non-virtual destructor. C ++ does not provide a prohibition mechanism similar to Java's final classes or C #'s sealed classes.
Sometimes it is convenient to provide a pure virtual destructor for a class. The pure virtualfunctions function causes the abstract class, that is, you cannot create this type of object. However, sometimes you want the class to be abstract, but there is no pure virtual function. What should we do?
The solution is simple: declare a pure virtual destructor in the class you want to Abstract:
Class AWOV {// AWOV = "Abstract w/oVirtuals"
Public:
Virtual ~ AWOV () = 0; // declare pure virtual destructor
};
This class has a purevirtual function, so it is abstract. Because it has a virtual destructor, you don't have to worry about the destructor. However, you must provide a definition for purevirtual destructor:
AWOV ::~ AWOV () {}// pure virtual destructor Definition
The method in which the Destructor works is: the class whose destructor is derived from the deepest layer is called first, and then calls each of its base classes. The compiler generates an destructor pair from its derived classes ~ AWOV call action, so you have to provide a definition for this function, otherwise the connector will complain.
The Rules for Providing virtual destructor for the base class only apply to the polymorphic (with polymorphism) base class. This base class is designed to "process derived class objects through the base class interface ". TimeKeeper is a multi-state base class, because it is expected to operate AtomicClock and WaterClock objects even if we only point to the pointers of the TimeKeeper type.
Not all base classes are designed for the purpose of polymorphism. For example, no standard string or STL container is designed as a base class, not to mention polymorphism. Although some classes are designed for base classes, they are not used for Polymorphism purposes. For example, Uncopyable and input_iterator_tag in the standard library are not designed to "process derived class objects through base class interfaces", so virtual destructor is not required.
· Virtual destructor should not be declared if it is not designed as a base class or for classes with Polymorphism
From pandawuwyj's column