Re: Calling pure virtual function from destructor
Dan Mattsson wrote:
[snip]
Is there a way to call a pure virtual function from the destructor of the
abstract class that declared it? Or is it Just Plain WrongT?
It's just plain wrong due to the design of C++. However, there are
work-arounds for specific cases (e.g. when the classes involved
provide default-constructors). Here is a small example that should get
you going:
#include <iostream>
/* Example base class.
*/
class CBase
{
public:
virtual ~CBase () {}
/* Should be provided by derived classes. This method will be called
* on the destruction of the object.
*/
virtual void OnShutDown () = 0;
protected:
/* This method should never be provided by derived classes. The sole
* purpose of this method is that the user is forced to use the
class
* CAdapterClass (see below) for creating instances of CBase-derived
classes.
*/
virtual void I_MADE_A_MISTAKE_BECAUSE_I_OVERWROTE_THIS_METHOD () =
0;
};
/* Example class that is derived from CBase.
*
* Note that this class should have a default constructor, or else we
won't
* be able to create an instance of this class through the adapter
class
* CAdapterClass (see
CBase::I_MADE_A_MISTAKE_BECAUSE_I_OVERWROTE_THIS_METHOD).
*/
class CDerived : public CBase
{
public:
virtual void OnShutDown ()
{
std::cout << "CDerived::OnShutdown called" << std::endl;
}
};
/* This adapter class can be used to instantiate objects of CBase-
derived classes.
* This adapter will ensure that the method OnShutDown will be called
for the
* most-derived class during the destruction of the instance.
*/
template<class t_BaseClass>
class CAdapterClass : public t_BaseClass
{
public:
virtual ~CAdapterClass ()
{
OnShutDown ();
}
protected:
virtual void I_MADE_A_MISTAKE_BECAUSE_I_OVERWROTE_THIS_METHOD ()
{
// There is nothing actually to be done here.
}
};
int main(int argc, char* argv[])
{
// The following is no longer possible, since CDerived does not
provide a method
// called I_MADE_A_MISTAKE_BECAUSE_I_OVERWROTE_THIS_METHOD.
//CDerived Derived;
// This works: The adapter class provides the method
// I_MADE_A_MISTAKE_BECAUSE_I_OVERWROTE_THIS_METHOD.
CAdapterClass<CDerived> Derived;
return 0;
}
This approach seems to have to faults:
(A) Nothing can prevent the writer of CDerived from providing his own
version of I_MADE_A_MISTAKE_BECAUSE_I_OVERWROTE_THIS_METHOD (at least
I see no way to prevent him).
(B) The adapter class will only work when the CDerived class provides
a deault constructor. This can be overcome by stuffing the class
CAdapterClass with constructors that will be needed throughout the
project:
template<class t_BaseClass>
class CAdapterClass : public t_BaseClass
{
public:
CAdapterClass ()
: t_BaseClass ()
{}
// For classes that have a constructor taking an int.
CAdapterClass (int i)
: t_BaseClass (i)
{}
// For classes that have a constructor taking a float.
CAdapterClass (float f)
: t_BaseClass (f)
{}
and so on. Note that the derived class does not have to provide all
the constructors of CAdapterClass since CAdapterClass is a template.
Regards,
Stuart