I have a class hierarchy which inherits QObject.
I need to perform some operations after construction (when the object is fully constructed) and before destruction (when the object is still complete).
The construction part is no problem, since I can control the construction of an object, making private its constructor and just making public the creator function which already can perform all the required operations.
The problem comes with the destructor. I have done more or less the same: hiding the destructor and providing a destroyer function which performs all the operations and then destroys the object.
Here is where the problem begins:my class hierarchy is used as part of the QJSEngine scripting module, which takes ownership of all the objects, and when it is time, it destroys them using the QObject's destructor, thus, bypassing my destroyer function. It is of no help declaring my destructors private, since the QJSEngine can always execute the QObject's destructor (and by the way, also can any piece of code which casts my pointers to QObject).
I require to perform this operations before calling the destructor, since I use some virtual functions, so I need to execute this BEFORE beginning the destruction process, so the virtual functions calls will not fail.
Is there a way to achieve this?
I attach a basic code snipped showing my problem:
class IBase: public QObject {
public:
template<typename T>
static IBase * create() {
IBase * obj=new T;
obj->afterConstruction();
return obj;
}
void destroy() {
this->beforeDestruction();
delete this;
}
protected:
IBase(): fBeforeDestruction(false){}
virtual ~IBase(){
//Try to perform operations, but it is too late....
if (!fBeforeDestruction)
doBeforeDestruction();
}
virtual void doAfterConstruction(){}
virtual void doBeforeDestruction(){}
private:
bool fBeforeDestruction;
void afterConstruction() {
doAfterConstruction();
}
void beforeDestruction(){
fBeforeDestruction=true;
doBeforeDestruction();
}
};
class TSubclass: public IBase {
protected:
TSubclass(){}
virtual ~TSubclass(){}
virtual void doAfterConstruction(){
qDebug()<<"AfterConstruction";
}
virtual void doBeforeDestruction(){
qDebug()<<"BeforeDestruction";
}
private:
friend class IBase;
};
int main(int argc, char *argv[])
{
//QObject *obj=new TSubclass() //Compile time error! Nice!
QObject *obj=IBase::create<TSubclass>();
delete obj;//Wrong! BeforeDestruction is NEVER shown!!! <---- How to change this behaviour?
IBase * obj2=IBase::create<TSubclass>();
//delete obj2; //Compile time error! Nice!
obj2->destroy(); //Nice!
}
EDIT:
After some comments, I have to add to the question that I want to do several operations before the destructor for two reasons:
Virtual calls: The virtual calls are not allowed inside the destructor, since they will not call the overriden functions, but only the functions in the current destroying class.
Dynamic casts downcasting: Some of the things to do involve donwcasting via dynamic_cast. dynamic_cast downcasting inside the destructors always fails.
EDIT 2:
The answer of Ezee works as I needed. Here is my complete code snippet, showing the code, with also a dynamic_cast:
template <typename T>
class TAfterConstructionBeforeDestruction: public T {
public:
~TAfterConstructionBeforeDestruction() {
this->beforeDestruction();
}
protected:
using T::T;
};
class IBase: public QObject {
public:
//Now it can be public, just as the one in QObject!
virtual ~IBase(){}
template<typename T>
static IBase * create() {
//Create a
IBase * obj=new TAfterConstructionBeforeDestruction<T>;
obj->afterConstruction();
return obj;
}
protected:
IBase(){}
virtual void afterConstruction(){}
virtual void beforeDestruction(){}
};
class TSubclass: public IBase {
public:
virtual ~TSubclass(){}
protected:
TSubclass(){}
virtual void afterConstruction(){
qDebug()<<"AfterConstruction";
}
virtual void beforeDestruction();
private:
friend class IBase;
};
class TSubclass2: public TSubclass {
public:
virtual ~TSubclass2(){}
protected:
TSubclass2(){}
virtual void beforeDestruction(){
qDebug()<<"BeforeDestruction from Subclass2";
TSubclass::beforeDestruction();
}
};
void TSubclass::beforeDestruction() {
qDebug()<<"BeforeDestruction";
TSubclass2 * sub=dynamic_cast<TSubclass2*>(this);
if (sub) {
qDebug()<<"We are actually a TSubclass2!";
}
}
int main(int argc, char *argv[])
{
//QObject *obj=new TSubclass() //Compile time error! Nice!
QObject *obj=IBase::create<TSubclass>();
delete obj;//Now it works fine!
IBase * obj2=IBase::create<TSubclass2>();
delete obj2; //It is still succeeding to dynamic_cast to TSubclass2 without any problem!
}