首页 > 编程语言 >C++对象析构顺序问题——由QObject::desroyed展开的思考

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

时间:2024-08-01 10:51:03浏览次数:8  
标签:obj 子类 C++ QObject 析构 MyObjectDerived main

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

标签:obj,子类,C++,QObject,析构,MyObjectDerived,main
From: https://www.cnblogs.com/3to4/p/18336193

相关文章

  • c++含有纯虚函数的虚基类是否能构造?
    前言笔者工作中有很多类派生自一个虚基类,但是这些派生类又有很多操作是大致相同,尤其是这些类都不能拷贝,所以需要删除拷贝构造函数和拷贝赋值运算符。最直接的想法是在虚基类里面删除拷贝构造函数和拷贝赋值运算符。但我想因为虚基类不能实例化,那是否可以定义常规构造函数、......
  • C/C++ 字面常量的注意事项
    在C/C++中使用字面常量时,有几个重要的注意事项需要考虑,以确保代码的准确性和可移植性。下面是一些关键要点:整数字面量:默认情况下,整数字面量是int类型。如果字面量的值超出了int的范围,它将被视为longint或longlongint,这取决于它的值和编译器。可以在整数字面量后添加L或l......
  • c++ 从txt读取数据 按照特殊字符拆分 gnss
      CMakeLists.txtcmake_minimum_required(VERSION3.10)project(ReadTextFile)#设置C++标准为C++11set(CMAKE_CXX_STANDARD11)set(CMAKE_CXX_STANDARD_REQUIREDTrue)#添加可执行文件,并链接主程序文件和自定义类的头文件add_executable(mainmain.cpp)......
  • 从C++看C#托管内存与非托管内存
    进程的内存一个exe文件,在没有运行时,其磁盘存储空间格式为函数代码段+全局变量段。加载为内存后,其进程内存模式增加为函数代码段+全局变量段+函数调用栈+堆区。我们重点讨论堆区。进程内存函数代码段全局变量段函数调用栈堆区托管堆与非托管堆C#inta=1......
  • 高精度加法、减法、乘法、除法(C++)
    1、引入在进行大整数运算中,因为在C++/C中整数,最大也就是unsignedlonglong也就才(1e19+8e18)位,如果要几百位的相加减就不行了,所以就要用高精度了,这里只在C++/C上使用有价值,在例如python、Java语言上无需写此算法,python可以无限大,Java里有相关库可以引入。2、入门的思路即为......
  • 基于VScode和C++ 实现Protobuf数据格式的通信
    目录1.Protobuf概述1.1定义1.2Protobuf的优势2.Protobuf语法3、序列号和反序列化3.1.pb.h头文件3.2序列化3.3反序列化4、测试用例Protobuf详细讲解链接1.Protobuf概述1.1定义protobuf也叫protocolbuffer是google的一种数据交换的格式,它独立于语......
  • UE4 C++ 多人游戏中的简单聊天窗口
    本质不管是客户端还是服务器在输入文字后,按下回车发送,将触发RPC调用。然后通过RPC将发送者,输入文本等信息,传入到服务器,然后通过多播RPC传播到所有客户端的聊天框。UIUI利用三个组件ScrollBox用于在服务器以及每个客户端上显示消息的载体TextBlock本地将信息通过一个一个的T......
  • Linux下C++动态链接库的生成以及使用
    目录一.前言二.生成动态链接库三.使用动态链接库一.前言这篇文章简单讨论一下Linux下如何使用gcc/g++生成和使用C++动态链接库(.so文件)。二.生成动态链接库先看下目录结构然后看下代码//demo.h#ifndefDEMO_H#defineDEMO_H#include<string>classDemo{......
  • 【C++BFS算法 二分查找】2812. 找出最安全路径
    本文涉及知识点C++BFS算法C++二分查找LeetCode2812.找出最安全路径给你一个下标从0开始、大小为nxn的二维矩阵grid,其中(r,c)表示:如果grid[r][c]=1,则表示一个存在小偷的单元格如果grid[r][c]=0,则表示一个空单元格你最开始位于单元格(0,0)。在......
  • 【C++】构造函数的深入学习
    一、初始化列表C++提供初始化列表语法用来初始化属性语法:构造函数():属性1(值1),属性2(值2)...{}classPeople{public://传统初始化操作Person(inta,intb,intc){A=a;B=b;C=c;}//初始化列表初始化属性Pers......