天天看点

qt类的构造与析构

一 说明

在qt代码中,我们经常给类的构造函数传入父指针,这个有什么用?类实例化后又是在什么时候释放的?

为了避免代码运行中出现内存泄漏,规范编程习惯,下面做一个验证。

其次也是对qt中对象树做一些了解,qt对象树学习文章:https://zhuanlan.zhihu.com/p/43523879

对象树在 GUI 编程中是非常非常有用的!当父对象被析构时子对象也会被析构,这样一定程度上简化了内存回收机制。

二 测试类设计

使用定时器打印信息,这样表示类实例化后是否被释放。

h文件

#ifndef TESTCLASS_H
#define TESTCLASS_H

#include <QObject>
#include <QTimer>

class TestClass : public QObject
{
    Q_OBJECT
public:
    explicit TestClass(QObject *parent = nullptr,QString info = "");

signals:

public slots:
private:
    QString myInfo;
};

#endif // TESTCLASS_H

           

cpp文件

#include "testclass.h"
#include <qDebug>

TestClass::TestClass(QObject *parent,QString info) :
    QObject(parent),
    myInfo(info)
{
    QTimer *time = new QTimer(this);
    connect(time,&QTimer::timeout,this,[=](){
        qDebug()<<Q_FUNC_INFO<<myInfo;
    });
    time->start(1000);
}

           

三 测试代码设计

使用mainwindows中加入一个按钮,使用按钮控制From类的创建与释放,然后再From类中使用各种方式创建TestClass类。

1 mainwindow类设计

h文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "form.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    Form *win;
};

#endif // MAINWINDOW_H

           

cpp文件

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    win = NULL;
}
MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::on_pushButton_clicked()
{
    if(win != NULL)
    {
        delete win;
        win = NULL;
    }
    else
    {
        win = new Form();
        win->show();
    }
}
           

3 From类测试的实现

h文件

#ifndef FORM_H
#define FORM_H

#include <QWidget>
#include "testclass.h"

namespace Ui {
class Form;
}

class Form : public QWidget
{
    Q_OBJECT

public:
    explicit Form(QWidget *parent = 0);
    ~Form();

private:
    Ui::Form *ui;
    TestClass c;
};

#endif // FORM_H

           

cpp文件

#include "form.h"
#include "ui_form.h"
Form::Form(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Form),
    c(NULL,"C")     //设置父对象无效,this对象释放的时候,c依据被释放
{
    ui->setupUi(this);

    TestClass *a = new TestClass(this,"A");         //等this对象(From)释放时释放
    TestClass *b = new TestClass(nullptr,"B");      //需要等进程关闭后,系统自动回收
    TestClass *e = new TestClass(parent,"E");       //需要等parent对象(Mainwindow)释放时释放
}
Form::~Form()
{
    delete ui;
}
           

3 测试结论

  1. new实例化,传入父类指针,随着父类指针释放的时候释放,子类前于父类执行析构函数。
  2. new实例化,传入父指针为空,即无父对象时,需要手动释放,即使用delete(一般放在析构函数中),否则需要等待进程关闭后系统回收(此情况为内存泄漏)。
  3. 类成员子类,实例化在构造的时候,释放的方式无法通过修改父对象修改,即使后期将父对象改为空。如:在From释放的时候,From的成员子类c,虽然后面改了c的父对象,在From对象释放的时候,c依据被释放。 原因分析: c作为成员,c的内存段在From内存范围内,在From释放后,其所有内存都要被释放,所以c也一定会被释放。

在From类代码的注释中也有体现,如果有兴趣的可以使用代码跑一下体验体验。