C++对象析构顺序问题——由QObject::desroyed展开的思考

C++对象析构顺序问题——由QObject::desroyed展开的思考

C++析构函数执行的顺序是最先执行继承链最末端的子类的,最后执行顶层的基类的。

QObject::destroyed(QObject* obj = nullptr) 信号在 Qt 文档中说是“在 obj 被完全析构时之前立即触发,并且不会被阻塞”。这里的“完全析构”指的是按照析构函数调用的顺序,存在析构了子类部分但还没析构基类部分的时刻。

因此,下例中会出现先打印析构函数中的输出,然后才调用槽函数的情况。不过,在对象还未被完全析构时,在析构函数中使用其成员(不管是子类部分还是基类部分)都是安全的,因为析构函数的执行是在OS释放这块内存之前。

#include <QCoreApplication>
#include <QDebug>

class MyObjectBase : public QObject
{
    Q_OBJECT
public:
    MyObjectBase() { qWarning() << "MyObjectBase 构造"; }
    virtual ~MyObjectBase() { qWarning() << "MyObjectBase 析构"; }
    void ownBaseMethod() { qWarning() << "父类的非虚方法" << m_father; }
    virtual void sharedMethod() { qWarning() << "父类的虚方法" << m_father; }
    int m_father = 100;
};

class MyObjectDerived final: public MyObjectBase
{
    Q_OBJECT
public:
    MyObjectDerived() { qWarning() << "MyObjectDerived 构造"; }
    virtual ~MyObjectDerived() { qWarning() << "MyObjectDerived 析构"; }
    void ownDerivedMethod() { qWarning() << "子类的独有方法" << m_father; }
    void sharedMethod() override { qWarning() << "子类重写的虚方法" << m_father << m_child; }
    int m_child = 200;
};

class Tracker : public QObject
{
    Q_OBJECT
public:
    Tracker(MyObjectDerived* target) : target(target) {}

public slots:
    void onDestructor() {
        qWarning() << "About to be destroyed!";
        target->ownBaseMethod();
        target->ownDerivedMethod();
        target->sharedMethod();
    }
private:
    MyObjectDerived* target;
};

int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);

    MyObjectDerived *obj = new MyObjectDerived();
    Tracker tracker(obj);
    QObject::connect(obj, &QObject::destroyed, &tracker, &Tracker::onDestructor);
    delete obj;

    return app.exec();
}
// moc main.cpp -o main.moc
#include "main.moc"

输出:

MyObjectBase 构造
MyObjectDerived 构造
MyObjectDerived 析构
MyObjectBase 析构
About to be destroyed!
父类的非虚方法 100
子类的独有方法 100
子类重写的虚方法 100 200
posted @ 2024-08-01 10:46  3的4次方  阅读(12)  评论(0编辑  收藏  举报