qt-C++笔记之自定义继承类初始化时涉及到parents的初始化

qt-C++笔记之自定义继承类初始化时涉及到parents的初始化

在这里插入图片描述

code review!

参考笔记
1.qt-C++笔记之父类窗口、父类控件、对象树的关系
2.qt-C++笔记之继承自 QWidget和继承自QObject 并通过 getWidget() 显示窗口或控件时的区别和原理
3.qt-C++笔记之自定义类继承自 QObjectQWidget 及开发方式详解
4.qt-C++笔记之自定义继承类初始化时涉及到parents的初始化

文章目录

  • qt-C++笔记之自定义继承类初始化时涉及到parents的初始化
    • 一.声明和实现在一起
      • 1. 构造函数中传递 `parent`
      • 2. 父类 `parent` 的作用
      • 3. 子类中未显式初始化父类 `parent` 的情况
      • 4. 动态设置父对象
      • 5. 使用智能指针管理对象
      • 6. 完整示例
    • 二.声明和实现分开
      • 1. 头文件(声明部分)
      • 2. 源文件(实现部分)
      • 3. 完整示例
        • 头文件(`MyWidget.h`)
        • 源文件(`MyWidget.cpp`)
        • 主程序(`main.cpp`)
      • 4. 关键点解析
        • 1. 头文件中声明构造函数
        • 2. 源文件中通过初始化列表传递 `parent`
        • 3. 使用 Qt 的对象树
        • 4. 在构造函数中初始化子对象
      • 5. 运行效果
      • 6. 总结

在 Qt 的 C++ 开发中,当我们创建一个类继承自 Qt 的某个类(比如 QObject 或者 QWidget)时,通常需要在构造函数中对父类的 parent 指针进行初始化。这是 Qt 的对象树管理机制的核心部分之一。

Qt 中的对象树通过 parent 指针来自动管理对象的生命周期。当一个父对象被销毁时,它会自动销毁所有的子对象。因此,合理地设置 parent 是很重要的。

以下是如何在继承类中初始化父类的 parent 的一些说明和示例:

一.声明和实现在一起

1. 构造函数中传递 parent

当定义自己的继承类时,可以在构造函数中接受一个 parent 参数,并将其传递给父类的构造函数。

#include <QWidget>

class MyWidget : public QWidget {
public:
    explicit MyWidget(QWidget *parent = nullptr) 
        : QWidget(parent)  // 调用父类的构造函数,初始化 parent
    {
        // 其他初始化代码
    }
};

在上面的代码中:

  • MyWidget 是从 QWidget 继承的。
  • 构造函数接受一个 QWidget *parent 参数,并将其传递给 QWidget 的构造函数来初始化父类的 parent

2. 父类 parent 的作用

parent 参数的作用是将当前对象附加到指定的父对象上,从而形成一个 Qt 对象树。例如:

QWidget *mainWindow = new QWidget;
MyWidget *childWidget = new MyWidget(mainWindow);  // 设置 mainWindow 为 parent

在这种情况下:

  • mainWindow 是父对象。
  • childWidget 被添加为 mainWindow 的子对象。
  • mainWindow 被销毁时,childWidget 会被自动销毁。

3. 子类中未显式初始化父类 parent 的情况

如果子类没有显式初始化父类的 parent 参数,默认情况下,Qt 对象的父类指针会被设置为 nullptr

class MyWidget : public QWidget {
public:
    MyWidget() {
        // 未显式传递 parent,parent 默认为 nullptr
    }
};

这意味着:

  • 对象不会自动附加到任何父对象。
  • 必须手动管理该对象的生命周期。

4. 动态设置父对象

即使在构造函数中没有传递 parent,也可以通过调用 setParent 方法在运行时动态设置父对象:

MyWidget *childWidget = new MyWidget;
childWidget->setParent(mainWindow);  // 动态设置 parent

这种方法在需要在对象创建后再决定其父对象时非常有用。

5. 使用智能指针管理对象

如果你不想依赖 Qt 的对象树,也可以使用标准的 C++ 智能指针(如 std::unique_ptrstd::shared_ptr)来管理对象的生命周期。但是,如果使用智能指针,就不要设置 parent,以免 Qt 和智能指针同时试图管理对象的生命周期,导致潜在的问题。

6. 完整示例

以下是一个完整的例子,展示如何正确初始化和使用 parent

#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>

class MyWidget : public QWidget {
public:
    explicit MyWidget(QWidget *parent = nullptr)
        : QWidget(parent)  // 初始化父类的 parent
    {
        QVBoxLayout *layout = new QVBoxLayout(this);
        QPushButton *button = new QPushButton("Click Me", this);

        layout->addWidget(button);
        setLayout(layout);
    }
};

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

    QWidget *mainWindow = new QWidget;
    MyWidget *childWidget = new MyWidget(mainWindow);

    mainWindow->resize(400, 300);
    mainWindow->show();

    return app.exec();
}

在这个例子中:

  • MyWidget 是一个自定义的 QWidget 子类。
  • MyWidget 的父对象是 mainWindow
  • mainWindow 被销毁时,MyWidget 也会被自动销毁。

二.声明和实现分开

当我们在 C++ 中将继承类的声明和实现分离时,涉及到 Qt 的 parent 初始化时,依然需要通过构造函数初始化列表在实现文件中将 parent 参数传递给父类的构造函数。以下是详细的分离步骤和示例。

1. 头文件(声明部分)

在头文件中声明类及构造函数,通常会为 parent 参数提供一个默认值(通常为 nullptr),这样在使用时可以选择是否显式传递父对象。

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>

class MyWidget : public QWidget {
    Q_OBJECT  // 如果使用信号和槽机制,必须添加 Q_OBJECT 宏

public:
    // 构造函数声明,带 parent 参数,默认值为 nullptr
    explicit MyWidget(QWidget *parent = nullptr);

    // 其他成员函数声明(如果有)
};

#endif // MYWIDGET_H

2. 源文件(实现部分)

在源文件中实现构造函数时,使用初始化列表将 parent 参数传递给父类的构造函数。

#include "MyWidget.h"

// 构造函数实现
MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)  // 将 parent 传递给 QWidget 的构造函数
{
    // 在这里编写其他初始化代码
}

3. 完整示例

以下是一个完整的例子,展示了如何分离声明和实现,同时正确初始化 parent

头文件(MyWidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>

class MyWidget : public QWidget {
    Q_OBJECT

public:
    explicit MyWidget(QWidget *parent = nullptr);  // 构造函数声明

private:
    QVBoxLayout *layout;  // 布局管理器
    QPushButton *button;  // 按钮
};

#endif // MYWIDGET_H
源文件(MyWidget.cpp
#include "MyWidget.h"

// 构造函数实现
MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)  // 将 parent 传递给父类 QWidget 的构造函数
{
    // 初始化布局和按钮
    layout = new QVBoxLayout(this);  // 将布局设置为当前 MyWidget 的子对象
    button = new QPushButton("Click Me", this);  // 将按钮设置为当前 MyWidget 的子对象

    layout->addWidget(button);  // 将按钮添加到布局中
    setLayout(layout);          // 应用布局到当前 widget
}
主程序(main.cpp
#include <QApplication>
#include "MyWidget.h"

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

    QWidget *mainWindow = new QWidget;  // 创建主窗口
    MyWidget *childWidget = new MyWidget(mainWindow);  // 将 mainWindow 作为 parent

    mainWindow->resize(400, 300);
    mainWindow->show();  // 显示主窗口

    return app.exec();
}

4. 关键点解析

1. 头文件中声明构造函数

explicit MyWidget(QWidget *parent = nullptr);

  • 使用 explicit 关键字可以防止隐式类型转换。
  • parent 参数的默认值为 nullptr,这样在不需要父对象时可以直接创建孤立的对象。
2. 源文件中通过初始化列表传递 parent

MyWidget::MyWidget(QWidget *parent) : QWidget(parent)

  • QWidget(parent) 是父类构造函数的调用,它会将 parent 初始化为当前对象的父对象。
  • 这是遵循 C++ 的构造函数初始化列表的标准写法。
3. 使用 Qt 的对象树

通过传递 parent,可以让 MyWidget 成为其父对象的一部分,Qt 的对象树将自动管理子对象的生命周期。例如:

  • 如果 MyWidget 的父对象是 mainWindow,销毁 mainWindow 会自动销毁其所有子对象,包括 MyWidget
4. 在构造函数中初始化子对象

MyWidget 的构造函数中,布局和按钮都通过 new 创建,并将当前对象(this)作为它们的父对象:

layout = new QVBoxLayout(this);  // 布局的父对象是 MyWidget
button = new QPushButton("Click Me", this);  // 按钮的父对象是 MyWidget

这确保了这些子对象会被 MyWidget 自动管理,无需手动释放。

5. 运行效果

运行上述程序后:

  • mainWindow 是主窗口。
  • MyWidget 是主窗口的子对象。
  • 当你关闭 mainWindow 时,MyWidget 会被自动销毁。
  • 按钮和布局也会被自动销毁,因为它们是 MyWidget 的子对象。

6. 总结

  1. 在继承类中,通常需要在构造函数中通过调用父类的构造函数来初始化 parent
  2. 合理设置 parent 可以让 Qt 对象树自动管理对象的生命周期。
  3. 如果不使用 parent,需要手动管理对象的生命周期。
  4. 动态设置 parent 或结合智能指针管理对象是可行的,但需要小心避免冲突。
  5. 在声明与实现分离时,parent 的初始化通过构造函数的初始化列表实现。
  6. 在头文件中声明构造函数时,可以为 parent 提供默认值 nullptr
  7. 在源文件中通过 : QWidget(parent) 调用父类构造函数进行初始化。
  8. 合理使用 Qt 的对象树机制,可以自动管理对象的生命周期,简化内存管理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/952218.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《图解HTTP》 学习日记

1.了解WEB以及网络基础 1.1使用HTTP协议访问WEB web页面显示:根据web浏览器地址栏中输入指定的URL,web浏览器从web服务端获取文件资源(resource)等信息&#xff0c;从而显示出web页面 1.2网络基础TCP/IP 通常使用的网络(包括 互联网)是在tcp/ip协议族的基础上运作的&#xf…

VSCODE使用Echarts组件库(不是vue)

第一步打开Echarts官网 Examples - Apache ECharts 第二步随便点击一个图形点击我圈的按钮 第三步

道品科技智慧农业与云平台:未来农业的变革之路

随着全球人口的不断增长&#xff0c;农业面临着前所未有的挑战。如何在有限的土地和资源上提高农业生产效率&#xff0c;成为了各国政府和农业从业者亟待解决的问题。智慧农业的兴起&#xff0c;结合云平台的应用&#xff0c;为农业的可持续发展提供了新的解决方案。 ## 一、智…

C++实现银行排队系统

网上看到的设计要求&#xff1a; 基本效果已经实现&#xff0c;希望大家帮忙指点指点。 程序中的一些基本模块 程序处理中的一些流程图 程序运行结果如下图&#xff1a; 程序代码如下&#xff1a; #include <iostream> #include <string> #include <random&g…

新版2024AndroidStudio项目目录结构拆分

如题 下载了最新版的android studio 发现目录结构和以前不一样 自动帮你合并了 如何层层抽丝剥茧呢 按照一下步骤即可解决问题&#xff01;

【Rust自学】11.6. 控制测试运行:并行和串行(连续执行)测试

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 11.6.1. 控制测试的运行方式 cargo test和cargo run一样&#xff0c;cargo test也会编译代码并生成一个二进制文件用于测试&#xff0c;…

linux:文件的创建/删除/复制/移动/查看/查找/权限/类型/压缩/打包

关于文件的关键词 创建 touch 删除 rm 复制 cp 权限 chmod 移动 mv 查看内容 cat(全部); head(前10行); tail(末尾10行); more,less 查找 find 压缩 gzip ; bzip 打包 tar 编辑 sed 创建文件 格式&#xff1a; touch 文件名 删除文件 复制文件 移动文件 查看文…

Docker 基础知识

背景 传统的linux的环境部署 命令多步骤多安装版本多 使用docker的话&#xff0c;一个命令就可以全部搞定 安装linux 之前安装过&#xff0c;所以直接使用的开罩进行复制的如果之前配置过静态地址&#xff0c;需要改成IPV4静态地址访问 安装docker 参考连接&#xff1a;https:/…

Docker 从入门到精通

文章目录 Ubuntu 安装Docker步骤前言1. 进入Docker官网&#xff0c;进入开发者页面2. 选择适合自己的安装方式3. 安装 Docker1.更新系统包&#xff0c;安装插件&#xff0c;创建秘钥及目录2.安装 Docker 软件包3.设置开机启动4.通过运行 hello-world 镜像验证安装是否成功 常见…

概率图模型01

机器学习中&#xff0c;线性回归、树、集成和概率图都属于典型的统计学习方法&#xff0c;概率图模型会更深入地体现出‘统计’两字 概率图模型的常见算法 概率图模型中的图 概率图模型如图主要分为两种&#xff0c;即贝叶斯网络和马尔可夫网络&#xff0c;有向图与无向图&…

Vue Router4

Vue Router 是 Vue.js 官方的路由管理器。Vue Router 基于路由和组件的映射关系&#xff0c;页面路径发生改变&#xff0c;就进行对应的组件切换。 安装&#xff1a; npm install vue-router。 基本 使用&#xff1a; // src/router/index.js import {createRouter, create…

深度学习知识点:LSTM

文章目录 1.应用现状2.发展历史3.基本结构4.LSTM和RNN的差异 1.应用现状 长短期记忆神经网络&#xff08;LSTM&#xff09;是一种特殊的循环神经网络(RNN)。原始的RNN在训练中&#xff0c;随着训练时间的加长以及网络层数的增多&#xff0c;很容易出现梯度爆炸或者梯度消失的问…

通过氧化最小化工艺提高SiC MOSFET迁移率的深入分析

标题 Insight Into Mobility Improvement by the Oxidation-Minimizing Process in SiC MOSFETs&#xff08;TED2024&#xff09; 文章的研究内容 文章的研究内容主要围绕氧化最小化工艺&#xff08;oxidation-minimizing process&#xff09;对碳化硅&#xff08;SiC&…

【Unity小技巧】解决Visual Code中文乱码

在Mac下使用VS Code打开代码时&#xff0c;中文注释显示乱码。 解决方法&#xff1a; VS Code&#xff1a;Setting -> Settings -> 搜索“autoGuessEncoding”&#xff0c;然后勾选上即可。 简体中文的Encoding是GB 2312。

maven 下载依赖 jhash:2.1.2 和对应 jar 包

原文地址 前言 25年新的一年&#xff0c;那就先更新一篇技术文章吧&#xff0c;这个是这几天刚遇到的一个有意思的bug&#xff0c;记录分享一下 原因分析 在使用maven加载一个项目的时&#xff0c;发现maven的依赖一直无法解析&#xff0c;更换阿里云镜像和中央仓库都没办法…

回归预测 | MATLAB基于RF-Adaboost多输入单输出回归预测

回归预测 | MATLAB基于RF-Adaboost多输入单输出回归预测 目录 回归预测 | MATLAB基于RF-Adaboost多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 回归预测 | MATLAB基于RF-Adaboost多输入单输出回归预测。 1.Matlab实现RF-Adaboost随机森林集成学习…

【网络协议】动态路由协议

前言 本文将概述动态路由协议&#xff0c;定义其概念&#xff0c;并了解其与静态路由的区别。同时将讨论动态路由协议相较于静态路由的优势&#xff0c;学习动态路由协议的不同类别以及无类别&#xff08;classless&#xff09;和有类别&#xff08;classful&#xff09;的特性…

基于SSM实现的垃圾分类平台系统功能实现二

一、前言介绍&#xff1a; 1.1 项目摘要 随着城市化进程的加速和居民生活水平的提高&#xff0c;城市生活垃圾的产量急剧增加&#xff0c;给城市环境管理带来了巨大压力。传统的垃圾处理方式&#xff0c;如填埋和焚烧&#xff0c;不仅占用大量土地资源&#xff0c;还可能对环…

如何实现多级缓存?

本文重点说一说在Java应用中&#xff0c;多级缓存如何实现。 多级缓存是比较常见的一种性能优化的手段&#xff0c;一般来说就是本地缓存分布式缓存。 本地缓存一般采用Caffeine和Guava&#xff0c;这两种是性能比较高的本地缓存的框架。他们都提供了缓存的过期、管理等功能。…

美摄科技为企业打造专属PC端视频编辑私有化部署方案

美摄科技&#xff0c;作为视频编辑技术的先行者&#xff0c;凭借其在多媒体处理领域的深厚积累&#xff0c;为企业量身打造了PC端视频编辑私有化部署解决方案&#xff0c;旨在帮助企业构建高效、安全、定制化的视频创作平台&#xff0c;赋能企业内容创新&#xff0c;提升品牌影…