Recently, it took me to prototype some of my old libraries, which I wrote as a young coder. I wanted to see which of them are still usable, and in the meantime I was going to check a few things about C + +, which I never had time to test on my own. One of the more surprising things is class inheritance combined with polymorphism and a destructor.
The thing looks rather simple:
class CRef{ public: virtual ~CRef(){ std::cout << "First Destructor" << std::endl; Free(); } virtual void Free(){ std::cout << "First Cleaning" << std::endl; } }; class CSomeClass : public CRef { public: virtual ~CSomeClass(){ std::cout << "Second Destructor" << std::endl; } virtual void Free(){ std::cout << "Second Cleaning" << std::endl; } };
We have classes with destructors, where the first one calls the cleaning method. In the planned concept, if we delete the object of the second class, the base class (CRef) will call the cleaning method of the extended class (CSomeClass) – easy? Of course. Working? Of course not ….
Results I should get:
First Destructor Second Cleaning Second Destructor
What I got:
First Destructor First Cleaning Second Destructor
The fact that both destructors ware called, is normal and it wasn’t even interesting. I was more surprised of an different situation where the cleaning method of the base class was called, and more tests only convinced me that the code does not have the right to work properly. The destructor is a type of method, in which we can call only the base class methods – forcing polymorphism by zeroing the method (virtual void Free () = 0;) in this class only leads to a linker error.
In other words – the only way to make this polymorphism to work properly in this case, is to call the Free(); by another, normally created method.
class CRef{ public: virtual ~CRef(){ std::cout << "First Destructor" << std::endl; } virtual void Free(){ std::cout << "First Cleaning" << std::endl; } void Release(){ Free(); } }; class CSomeClass : public CRef { public: virtual ~CSomeClass(){ std::cout << "Second Destructor" << std::endl; } virtual void Free(){ std::cout << "Second Cleaning" << std::endl; } };
…
pClass->Release();
delete pClass;
…
This code will successfully execute, and it will call the method of the inherited class. Its a little annoying thing, but its nothing that can not be avoided by a few clever macros