This concerns the second question about declaring a virtual destructor for an abstract base class (for example, at least one member function is pure virtual). Here's a real-world example of the LLVM clang ++ compiler that catches a potential problem. This happened with the version of the command line tools provided by Apple Developer for Mac OS X Mavericks.
Suppose you have a set of derived classes that end up having a parent with an abstract base class to define a common interface. Then you need to have a storage container, such as a vector, that is intentionally declared to hold a pointer to an abstract base class for each element. Later, following good technical practice, the container elements should be โdeletedโ and the memory returned to the heap. The easiest way to do this is to cross the vector element over the element and call the delete operation on each of them.
Well, if the abstract base class does not declare the destructor as virtual, the clang ++ compiler gives a friendly warning about calling a non-virtual destructor in an abstract class. Keep in mind that in fact, only derived classes are allocated from the heap using the new operator. The pointer type of the derived class from the inheritance relation is indeed an abstract type of the base class (for example, the is-a relation).
If the abstract destructor of the base class is not virtual, then how will the handle to the correct derived class be called to free memory? In the best case, the compiler knows better (at least potentially with C ++ 11) and makes this possible. If the -Wall option of the compiler is enabled, then a compilation warning should appear. However, in the worst case, the destructor of the derived class is never reached, and the memory is never returned to the heap. Therefore, a memory leak is currently occurring, which can be very difficult to track and repair. All that is required is a one-time addition of the "virtual" to the declaration of the destructor of the abstract base class.
Code example:
class abstractBase { public: abstractBase() { }; ~abstractBase() { }; virtual int foo() = 0; }; class derived : abstractBase { public: derived() { }; ~derived() { }; int foo() override { return 42; } }; // // Later on, within a file like main.cpp . . . // (header file includes are assumed to be satisfied) // vector<abstractBase*> v; for (auto i = 0; i < 1000; i++) { v.push_back(new derived()); } // // do other stuff, logic, what not // // // heap is running low, release memory from vector v above // for (auto i = v.begin(); i < v.end(); i++) { delete (*i); // problem is right here, how to find the derived class' destructor? }
To eliminate this potential memory leak, the abstract base class must declare its destructor virtual. Nothing more is required. Now the abstract base class becomes the following:
class abstractBase { public: abstractBase() { }; virtual ~abstractBase() { }; // insert virtual right here virtual int foo() = 0; }
Note that the abstract base class currently has empty constructor and destructor bodies. As stated in Lightness, the compiler creates a default constructor, a destructor, and a copy constructor for an abstract base class (if it is not defined by an engineer). It is strongly recommended that you check out any of the C ++ programming language editions by the C ++ creator, Bjarne Stroustrup, for more information on abstract base classes.