天天看點

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類代碼的注釋中也有展現,如果有興趣的可以使用代碼跑一下體驗體驗。