QObject 的构建/销毁顺序

  当QObject在堆上创建(也就是说,使用new操作符),同时也会以任意顺序创建一棵树;稍后,树中的对象也会以任意顺序被销毁。当树中的对象被删除掉时,如果这个对象有父对象,析构函数会自动将其从父对象的列表中删除。如果这个对象有子对象,析构函数会自动删除掉所有子对象。不管析构的顺序如何,没有QObject被删除两次。

  当QObject在栈上被创建,其行为也是类似的。按理说,析构顺序也不会有任何问题。请看下面的代码片段:

     int main()
    {
       QWidget window;
       QPushButton quit("Quit", &window);
       ...
     }

  父对象window和子对象quit都是QObject,因为QPushButton继承自QWidget,而QWidget继承自QObject。这个代码是正确的:quit的析构函数不会被调用两次,因为 C++ 语言标准(ISO/IEC 14882:2003)规定,局部对象的析构函数调用顺序与其构造函数顺序相反。因此,子对象quit的析构函数首先被调用,它在父对象window的析构函数调用之前,将其自身从父对象中删除。

  但是,现在考虑如果我们颠倒了构造函数的顺序,请看下面的代码片段:

   int main()
  {
      QPushButton quit("Quit");
      QWidget window;
 
      quit.setParent(&window);
      ...
   }

  在这种情况下,析构函数的调用顺序将出现问题。父对象的析构函数将首先被调用,因为它是最后创建的。然后在调用子对象quit的析构函数时就会发生错误,因为quit是一个局部变量。当quit超出作用域时,它的析构函数又会被调用一次。这个时候会是正确的,但是致命错误已经出现了。

  所以qt中new子窗体指明父窗体时,无需delete,关闭父窗体,子窗体也会相应关闭。如果new的子窗体未指明父窗体指针,关闭父窗体时,子窗体不关闭。可以这样不指明父窗体指针,在父窗体析构函数中delete子窗体,但需要先在父窗体closeEvent中close子窗体,这样才能进入父窗体析构函数,然后delete子窗体。

来源:http://my.oschina.net/CgShare/blog/193092?p=1

<think>好的,用户之前已经询问过如何在Qt中实现跨类信号接收,现在他们要求提供一个具体的实例。我需要确保这次的回答更加详细,并且提供一个完整的代码示例,涵盖发送类、接收类以及主函数的实现。 首先,用户之前的问题已经得到了理论上的步骤说明,现在需要具体例子,所以他们可能在实际编码中遇到了问题,或者想通过实例加深理解。我需要确保代码正确,语法无误,并且能够直接运行,这样用户可以直接复制粘贴进行测试。 接下来,我应该回顾之前的回答结构,确保这次回答同样结构清晰。可能需要分步骤展示类定义、连接方式和触发信号的代码。同时,用户可能需要了解如何将这些类集成到主函数中,特别是如何在Qt应用程序中使用它们,比如在main.cpp中创建对象并建立连接。 还需要注意Qt的元对象系统,确保每个类都有Q_OBJECT宏,否则信号和槽无法正常工作。这也是用户可能会遇到的常见问题,所以在示例中应该明确标出这一点,避免用户遗漏。 另外,线程问题也是需要考虑的。如果在不同线程中,可能需要使用Qt::QueuedConnection,但在这个示例中,可能保持简单,使用默认的连接方式,因为用户可能刚开始学习,不需要复杂的情况。不过,可以在关键点说明中提到这一点,以供用户扩展知识。 用户可能的疑问包括如何触发信号,是否需要手动调用someMethod,或者如何在实际应用中触发信号。因此,示例中应该在主函数里模拟触发信号的动作,比如调用一个方法或直接emit,但需要符合实际的使用场景,比如在按钮点击时触发,但为了简化,可能在main中直接调用emit。 不过,在Qt中,直接在主函数里调用emit可能不太常见,通常是通过用户交互触发。但为了示例的简洁,可以允许这样的做法,或者创建一个简单的定时器或按钮来触发信号。不过,这可能会增加代码的复杂度,所以可能需要权衡。这里保持简单,直接在main中调用emit,但需要确保对象的存在和正确性。 另外,需要检查信号和槽的参数是否一致,类型和顺序都要匹配,这在示例中必须正确,否则用户复制代码后无法运行。例如,信号是发送QString,槽函数接收QString,不能有类型不匹配的情况。 最后,提供编译和运行的说明,确保用户知道如何构建项目,可能需要提醒用户使用qmake和正确的.pro文件配置,特别是需要添加QT += core gui(如果涉及GUI的话),但在这个示例中可能只是控制台应用,所以需要明确说明。 总结下来,我需要构建一个包含ClassA(发送者)、ClassB(接收者)、main函数的完整示例,演示信号发送和跨类接收,并确保代码正确,注释清晰,关键点说明到位,帮助用户理解和解决潜在问题。</think>以下是一个完整的Qt跨类信号/槽通信示例,包含发送类、接收类和主程序逻辑: ### 实例场景 - **发送类** `TemperatureSensor`:模拟温度传感器,当温度变化时发送信号 - **接收类** `DisplayPanel`:显示面板,接收温度值并打印 - **主程序**:创建对象并建立跨类连接 --- ### 1. 温度传感器类(发送信号) ```cpp // temperaturesensor.h #include <QObject> class TemperatureSensor : public QObject { Q_OBJECT // 必须包含Q_OBJECT宏 public: explicit TemperatureSensor(QObject *parent = nullptr) : QObject(parent), m_temperature(25.0) {} void checkTemperature() { m_temperature += 0.5; // 模拟温度变化 emit temperatureChanged(m_temperature); // 触发信号 } signals: void temperatureChanged(double newTemp); // 温度变化信号 private: double m_temperature; }; ``` --- ### 2. 显示面板类(接收信号) ```cpp // displaypanel.h #include <QObject> #include <QDebug> class DisplayPanel : public QObject { Q_OBJECT public slots: void updateDisplay(double temp) { // 接收温度值的槽 qDebug() << "[显示面板] 当前温度:" << temp << "°C"; if(temp > 30.0) { qDebug() << "警告:温度过高!"; } } }; ``` --- ### 3. 主程序实现 ```cpp // main.cpp #include <QCoreApplication> #include "temperaturesensor.h" #include "displaypanel.h" int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); // 创建跨类通信对象 TemperatureSensor sensor; DisplayPanel display; // 建立信号槽连接 QObject::connect( &sensor, &TemperatureSensor::temperatureChanged, &display, &DisplayPanel::updateDisplay ); // 模拟温度检测循环 for(int i=0; i<5; ++i) { sensor.checkTemperature(); // 触发信号 QThread::sleep(1); // 等待1秒 } return app.exec(); } ``` --- ### 4. 输出结果 ```plaintext [显示面板] 当前温度:25.5 °C [显示面板] 当前温度:26 °C [显示面板] 当前温度:26.5 °C [显示面板] 当前温度:27 °C [显示面板] 当前温度:27.5 °C ``` --- ### 关键实现细节 1. **生命周期管理** `sensor`和`display`对象在`main()`函数作用域内创建,确保连接期间有效 2. **参数类型匹配** 信号`temperatureChanged(double)`与槽`updateDisplay(double)`严格匹配 3. **跨线程扩展** 若传感器在独立线程运行,需修改连接方式: ```cpp QObject::connect(&sensor, &TemperatureSensor::temperatureChanged, &display, &DisplayPanel::updateDisplay, Qt::QueuedConnection); // 队列连接保证线程安全 ``` 4. **调试技巧** 检查连接是否成功: ```cpp bool success = QObject::connect(...); qDebug() << "连接状态:" << success; // 输出true/false ``` --- ### 常见问题解决方案 **Q1:编译时提示`undefined reference to vtable`** ➔ 确保所有含信号/槽的类都: - 包含`Q_OBJECT`宏 - 执行`qmake`重新生成Makefile **Q2:信号触发但槽函数未执行** ➔ 检查: 1. 对象是否已被销毁 2. 线程模型是否匹配(GUI操作需在主线程) 3. 连接类型是否合适 **Q3:如何传递自定义数据类型?** ➔ 需要注册元类型: ```cpp // 在连接前添加 qRegisterMetaType<MyCustomType>("MyCustomType"); ``` --- 这个实例展示了Qt跨类通信的核心实现模式,可直接用于设备状态监控、UI更新等实际开发场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值