【发布时间】:2014-09-11 11:17:24
【问题描述】:
我有一个继承 QObject 的类层次结构。
我需要在构造之后(对象完全构造时)和销毁之前(对象仍然完整时)执行一些操作。
构造部分没有问题,因为我可以控制对象的构造,将其构造函数设为私有,并将已经可以执行所有必需操作的创建函数公开。
问题在于析构函数。我或多或少做了同样的事情:隐藏析构函数并提供一个销毁函数,该函数执行所有操作,然后销毁对象。
这里是问题开始的地方:我的类层次结构被用作 QJSEngine 脚本模块的一部分,它拥有所有对象的所有权,到时候,它使用 QObject 的析构函数销毁它们,从而绕过我的析构函数功能。将我的析构函数声明为私有是没有帮助的,因为 QJSEngine 总是可以执行 QObject 的析构函数(顺便说一句,任何将我的指针转换为 QObject 的代码也可以)。
我需要在调用析构函数之前执行这个操作,因为我使用了一些虚函数,所以我需要在开始销毁过程之前执行这个操作,所以虚函数调用不会失败。
有没有办法做到这一点?
我附上一段基本代码,显示我的问题:
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!
}
编辑:
在一些cmets之后,我不得不补充说我想在析构函数之前做几个操作,原因有两个:
虚拟调用:在析构函数内部不允许虚拟调用,因为它们不会调用被覆盖的函数,而只会调用当前销毁类中的函数。
动态转换向下转换:一些要做的事情涉及通过 dynamic_cast 进行转换。析构函数内的 dynamic_cast 向下转换总是失败。
编辑 2:
Ezee 的答案按我的需要工作。这是我的完整代码 sn-p,显示代码,还有一个 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!
}
【问题讨论】:
-
你的类中缺少 Q_OBJECT 宏,为什么还要隐藏析构函数?
-
这里不需要Q_OBJECT,因为没有信号/槽/属性
-
您声明您需要在“对象仍然完整时”在销毁之前执行操作 - 为什么您不能在析构函数本身中执行这些操作?对象在退出析构函数之前仍然是“完整的”。
-
尽管描述很长,但我仍然不明白为什么不能只将破坏代码放在析构函数中。
-
@Merlin069 和 C.R. 我不能把我的代码放在析构函数中,原因有两个:在析构函数本身中调用虚拟调用(这不会做我想要的,因为它不会调用被覆盖的函数) 并且因为我做了几个 dynamic_casts 向下转换,这在析构函数中失败了。我更新了我的问题
标签: c++ qt inheritance