1. QObject(parent) 核心含义

1. QObject(parent) 核心含义

cpp 复制代码
UdpSender::UdpSender(QObject *parent, ...)
    : QObject(parent)  // 初始化列表:调用父类QObject的构造函数
{
    // 函数体
}

这句代码的本质是:在创建 UdpSender 对象时,先调用它的父类 QObject 的构造函数,并将 parent 指针传递给父类。

拆解说明:

  • : 后面是「构造函数初始化列表」:C++ 规定,子类构造时必须先初始化父类成员,这里就是显式调用父类 QObject 的构造函数;
  • QObject(parent):调用 QObject 类的构造函数 QObject(QObject *parent = nullptr),把传入的 parent 指针传给父类;
  • 因为 UdpSender 继承自 QObject,所以必须通过这种方式初始化父类(如果不写,编译器会自动调用 QObject() 无参构造,即 parent=nullptr)。

2. parent 指针的核心作用(Qt 父子对象机制)

这是 Qt 最核心的内存管理机制,parent 指针的作用只有一个:建立「父子对象关系」,让父对象自动管理子对象的内存。

举个具体例子(结合我们的代码):

cpp 复制代码
// 在MainWindow中创建UdpSender,把this(MainWindow对象)作为parent
UdpSender *sender = new UdpSender(this); 

此时:

  • sender(UdpSender 对象)是「子对象」,MainWindow 对象是「父对象」;
  • 当 MainWindow 对象被销毁时(比如关闭窗口),会自动调用 sender->deleteLater(),销毁这个 UdpSender 对象;
  • 你不需要手动写 delete sender;,Qt 会自动帮你释放内存,避免内存泄漏。

再看我们代码中的 QUdpSocket 创建:

cpp 复制代码
m_udpSocket = new QUdpSocket(this);

这里把 this(UdpSender 对象)作为 QUdpSocket 的 parent,意味着:

  • m_udpSocket 是 UdpSender 的子对象;
  • 当 UdpSender 被销毁时,会自动销毁 m_udpSocket,无需手动释放。

3. 为什么必须写 QObject(parent)?

(1)不写的后果

如果我们把初始化列表的 QObject(parent) 删掉:

cpp 复制代码
// 错误写法
UdpSender::UdpSender(QObject *parent, ...)
{
    // 编译器会自动调用 QObject() 无参构造,等价于 QObject(nullptr)
}

此时 UdpSender 对象的 parent 会被默认设为 nullptr,导致:

  • 该对象脱离 Qt 的父子管理体系,变成「孤儿对象」;
  • 你必须手动 delete 这个对象,否则会造成内存泄漏;
  • 无法利用 Qt 的信号槽机制的一些特性(比如线程间信号传递)。

(2)写了的好处

  1. 自动内存管理:父对象销毁时,子对象自动销毁,杜绝内存泄漏;
  2. 信号槽线程安全:父子对象在同一线程时,信号槽无需手动指定连接方式;
  3. 对象树遍历 :可以通过 parent() 获取父对象,或 children() 获取所有子对象(比如调试时查看对象关系)。

4. 完整示例:父子对象的生命周期

cpp 复制代码
#include "UdpSender.h"
#include <QApplication>
#include <QMainWindow>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    QMainWindow *window = new QMainWindow(); // 父对象
    UdpSender *sender = new UdpSender(window); // sender的parent是window

    window->show();
    int ret = a.exec();

    delete window; // 销毁window
    // 此时sender会被window自动销毁,无需手动delete sender;

    return ret;
}
  • 执行 delete window; 时,window 会遍历所有子对象,调用它们的 deleteLater();
  • sender 被销毁时,又会遍历它的子对象(比如 m_udpSocket),销毁 QUdpSocket;
  • 整个过程无需手动管理子对象内存,这是 Qt 比原生 C++ 更易用的核心原因。

5. 补充:parent 的默认值

在我们的构造函数声明中,parent 有默认值 nullptr:

cpp 复制代码
explicit UdpSender(QObject *parent = nullptr, ...);

这意味着:

  • 如果你创建对象时不传入 parent,比如 UdpSender *sender = new UdpSender();,则 parent=nullptr,该对象无父对象;
  • 如果你传入 parent,则建立父子关系,享受自动内存管理。

总结

  1. QObject(parent) 是调用父类 QObject 的构造函数 ,将 parent 指针传递给父类,建立父子对象关系;
  2. parent 指针的核心作用是Qt 自动内存管理:父对象销毁时,子对象自动销毁,避免内存泄漏;
  3. 继承自 QObject 的类(如 UdpSender/UdpReceiver),构造函数必须通过初始化列表调用 QObject(parent),否则会失去 Qt 的内存管理特性。
相关推荐
涛思数据(TDengine)5 分钟前
TDengine TSDB 3.4.3.3 上线:流计算分层闭环、虚拟表跨层引用,查询关联一次写完
数据库·人工智能·数据分析·时序数据库·tdengine·工业
远方16097 分钟前
118-五大进程LGWR DBWn CKPT SMON PMON 与存储故障-文件系统对照
大数据·数据库·sql·oracle·database
ss2739 分钟前
AI时代首先数据库-PostgreSQL实战笔记 | 17 PostgreSQL SQL高级查询:窗口函数、CASE、COALESCE
数据库·笔记·postgresql
远方160915 分钟前
119-Oracle CDB 下修改和重置 SYS SYSTEM密码记录
大数据·数据库·sql·oracle·database
橙光成长19 分钟前
Context Mode 深度解析:用沙盒、SQLite 与钩子路由,把 AI 编码 Agent 的上下文消耗削减 98%
数据库·人工智能·sqlite
数据库小学妹34 分钟前
MySQL时区问题排查:TIMESTAMP和DATETIME的区别与跨时区对账踩坑
数据库·mysql·datetime·时区·timestamp·跨时区对账
创世虚拟世界1 小时前
把 3D 虚拟世界拉到本地:vibe coding 的手感,是从看见自己那一行改动开始的
javascript·数据库·人工智能·3d·gitee·虚拟现实
俊昭喜喜里1 小时前
Springboot的Mybatis中的条件构造器
数据库·mybatis
倔强的石头_1 小时前
列存储到底快在哪 在金仓KES上把原理和实操跑了一遍
数据库