1、区别Qt中父子关系与C++中的继承关系两个概念
本文使用父亲、儿子来表示Qt中的父子关系,使用基类、子类表示C++中的继承关系。
首先,我们通过创建两个类来更好地理解这两个概念的区别,分别是一个继承自QMainWindow类的MainWindow类和一个继承自QPushButton的PushButton类。具体如下:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr)
{}
~MainWindow()
{
std::cout << "~MainWindow()\n" << std::flush;
}
};
class PushButton : public QPushButton
{
Q_OBJECT
public:
PushButton(QWidget *parent = nullptr)
{}
~PushButton()
{
std::cout << "~PushButton()\n" << std::flush;
}
};
?然后运行下面的main函数:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow* w = new MainWindow();
w->setWindowTitle("MainWindow");
PushButton* p = new PushButton();
p->setParent(w);
p->resize(150, 50);
p->move(30, 30);
p->setText("Button");
w->show();
a.exec();
delete w;
}
结果如下图:
在关闭该窗口后,输出为:
~MainWindow()
~PushButton()
由于对象树的机制,在关闭MainWindow后,首先依附与它的PushButton将首先被销毁,但输出却先为~MainWindow()后为~PushButon()。
其实,宏观上看,确实是先销毁PushButton,再销毁MainWindow()。但C++语言的机理却使得~MainWindow()先输出。其实,对象树的实现是在QObject这一基类的析构函数中实现的,所有派生自QObject的类都继承了这一机制。在进行delete w时,首先执行了MainWindow的析构函数,输出了~MainWindow(),然后C++去执行MainWindow的基类QMainWindow的析构函数,然后一层一层向上执行,最终执行到QObject的析构函数,在QObject中执行对象树机制,首先销毁窗口的儿子PushButton,此时由于QObject的析构函数并未执行完毕,所以MainWindow也并未销毁,所以PushButton是先于MainWindow销毁的,只是先输出~MainWindow()显得不符合直觉而已。
2、不要手动销毁有父亲的Qt对象
执行下面代码:
#include "mainwindow.h"
#include "pushbutton.h"
#include <QApplication>
#include <iostream>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow* w = new MainWindow();
w->setWindowTitle("MainWindow");
PushButton* p = new PushButton();
p->setParent(w);
p->resize(150, 50);
p->move(30, 30);
p->setText("Button");
w->show();
a.exec();
delete w;
std::cout << "w was deleted\n" << std::flush;
delete p;
std::cout << "p was deleted\n" << std::flush;
}
将会得到如下输出:
~MainWindow()
~PushButton()
w was deleted
20:16:19: 程序异常结束。
?因为在delete w时已经通过对象树机制完成了p对象的销毁,如果此时再次手动delete p,将会报错。但是如果首先销毁p,再次销毁w,不会报错。可能是在销毁w时,对象树机制会去检查p对象是否被销毁,只有p对象未被销毁,才会执行对象树机制销毁p对象。但是千万不能首先销毁父亲,而后销毁儿子。
#include "mainwindow.h"
#include "pushbutton.h"
#include <QApplication>
#include <iostream>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow* w = new MainWindow();
w->setWindowTitle("MainWindow");
PushButton* p = new PushButton();
p->setParent(w);
p->resize(150, 50);
p->move(30, 30);
p->setText("Button");
w->show();
a.exec();
delete p;
std::cout << "p was deleted\n" << std::flush;
delete w;
std::cout << "w was deleted\n" << std::flush;
}
~PushButton()
p was deleted
~MainWindow()
w was deleted
|