class AncestorClass
{
public:
AncestorClass() {}
virtual ~AncestorClass() {}
static void* operator new(size_t _size)
{
cout << "AncestorClass new" << endl;
AncestorClass* _ptr = ::new AncestorClass();
if (_ptr) _ptr->Initialize();
return _ptr;
}
static void operator delete(void* _ptr)
{
cout << "AncestorClass delete" << endl;
if (_ptr) ((AncestorClass*)_ptr)->Finalize();
::delete _ptr;
}
virtual void Initialize()
{
cout << "Ancestor Initialize" << endl;
}
virtual void Finalize()
{
cout << "Ancestor Finalize" << endl;
}
};
class DerivedClass : public AncestorClass
{
public:
DerivedClass() {}
virtual ~DerivedClass() {}
static void* operator new(size_t _size)
{
cout << "DerivedClass new" << endl;
DerivedClass* _ptr = ::new DerivedClass();
if (_ptr) _ptr->Initialize();
return _ptr;
}
static void operator delete(void* _ptr)
{
cout << "DerivedClass delete" << endl;
((DerivedClass*)_ptr)->Finalize();
::delete _ptr;
}
virtual void Initialize()
{
cout << "DerivedClass Initialize" << endl;
}
virtual void Finalize()
{
cout << "DerivedClass Finalize" << endl;
}
};
int main()
{
AncestorClass* t = new DerivedClass;
delete t;
return 0;
}
What I expected result is...
DerivedClass new
DerivedClass Initialize
DerivedClass delete
DerivedClass Finalize
but what in real is...
DerivedClass new
DerivedClass Initialize
DerivedClass delete
AncestorClass Finalize
Where's my problem and how to fix it?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
The problem is your expectation that DerivedClass::Finalize will be
called from DerivedClass::delete. An object's destructor is called
_before_ the memory is released. Consequently, you're calling
Finalize() after the destructor returns. The Derived object no longer
exists at that stage - just some scraps in memory where it was during
it's lifetime, which you call into rather gamely. Put some couts in
the destructors and you should see it all happening.
Tony
You were lucky that this didn't crash. The void * you get as argument in
your operator delete points to *raw memory*, and not to a class in
particular. Specifically, the memory address you get there does not need
to be identical to the address of the first byte of the object that has,
at this point, already been destructed.
To fix this, call Finalize() in the destructor of the class (I wonder
why you didn't in first place).
Side information: what you see here is undefined behaivour - you cast a
raw memory pointer to a class, though the memory no longer contains that
class (nor has it to be related). The reason why this "kind of" worked
here is that you have been lucky and the first byte of the object is
identical to the address you got as argument (not required to be so).
Whenever the destructor of the derived class completed, the derived
class is no longer "derived", but becomes the base class, i.e. virtual
functions called in the base class destructor do not go into the methods
of the derived class. This is because the derived class "is no more" as
soon as its destructor completed. A typical implementation strategy for
this is that the compiler generates code that overwrites the virtual
function table of the derived object with the virtual function table of
the base class. You luckily found something in the memory that "looked"
like the base object for this reason.
However, please see the remarks above: Don't do that. If you want to
call a method of the object, make sure that the object exists. It
doesn't in operator delete, you only have raw memory there and nothing
else (that's why it is static in first place).
So long,
Thomas