本文的前半部分是对一篇公众号的文章的转载,后半部分是自己补充有关对象树的知识。
如何理解下面段代码的第二行QWidget(parent)
1 Widget::Widget(QWidget *parent) :
2 QWidget(parent)
3 {
4 }
在讲解原因之前,先请大家看下面的一个例子
#include
using namespace std;
class Base
{
public:
Base() :m_num(0){
cout << "this is Base()" << endl;
}
Base(int val):m_num(val){
cout << "this is Base(int val)" << endl;
}
private:
int m_num;
};
1 上方代码定义了一个基类Base,并且有两个构造函数,一个是默认构造函数,一个是有一个整型参数的构造函数。
class BaseChild: public Base
{
public:
BaseChild(){
cout << "this is BaseChild()" << endl;
}
BaseChild(int val): Base(val){
cout << "this is BaseChild(val)" << endl;
}
private:
int m_num;
};
2 上方代码定义了一个BaseChild类,并继承Base类,同样的,它也定义了两个构造函数,一个默认,一个有整型参数。
int main(int argc, char *argv[])
{
BaseChild child1;
BaseChild child2(5);
return 0;
}
3 main函数实例化了两个子类实例,child1,child2。child1调用默认构造函数。child2调用有整型参数的构造函数。
现在,我们运行程序,会有如下打印:
看到了吗,我们发现:
所以我们回头看BaseChild的构造函数
BaseChild(int val): Base(val){
cout << "this is BaseChild(val)" << endl;
}
细心的同学,可能早就发现了,初始化列表中的Base(val)正是调用了我们Base基类的有参构造函数,而这样的写法就刚好是我们开头代码中的那段
Widget::Widget(QWidget *parent) :QWidget(parent)
所以Widget是调用了QWidget下面的构造函数
QWidget(QWidget* parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
所以得出如下总结:
基类的构造函数是不能被继承的,在声明派生类时,派生类并没有把基类的构造函数继承过来。因此,对继承过来的基类成员的初始化工作也要由派生类的构造函数承担。
如果希望在执行派生类的构造函数时,使派生类的数据成员和基类的数据成员同时都被初始化。思路是:在执行派生类的构造函数时,调用基类的构造函数。
以上总结,也告诉我们,当定义一个类时,最好为该类定义默认构造函数。
好的,那么我们又提出一个问题,“调用QWidget(parent)这个构造函数,QWidget父类都做了哪些动作呢?”
下面是QWidget源码中的一部分节选:
QWidget::QWidget( QWidget *parent, const char *name, WFlags f )
: QObject( parent, name ), QPaintDevice( PDT_WIDGET ),
pal( parent ? parent->palette() // use parent's palette
: *qApp->palette() ) // use application palette
{
if ( parent ) {
QChildEvent *e = new QChildEvent( Event_ChildInserted, this );
QApplication::postEvent( parent, e );
}
}
大家从上面可以看出,如果parent参数非空的话,那么该构造函数使用了其父窗口的调色板,并且发送了QChildEvent事件,这会让新的窗口成为parent所指窗口的子窗口,那么当父窗口被删除时,子窗口也会自动的被删除。
这其实是用到了Qt对象树的概念。
假如Base类和BaseChild类也有对象树概念的话,我们可以近似认为它们的对象树如图所示。
QWidget是用户操作的原子接口,它从窗口系统中接收鼠标,键盘以及其他事件,并绘制图形界面。QT提供的默认窗口基类只有QMainWindow、QWidget、和QDialog这三种,QMainWindow是带有菜单栏和工具栏的主窗口类,QDialog是各种对话框的基类,而它们全部继承自QWidget。不仅如此,所有的窗口部件都继承自QWidget,继承关系如图所示。
一个没有父窗口部件的窗口部件一直是顶级窗口部件。非顶级窗口部件是父窗口的子部件。QWidget构造函数有两个参数:QWidget *parent = 0,Qt::WindowFlags f = 0
。parent即父窗口,默认为0,即没有父窗口,是顶级窗口,如果指定parent值则当前窗体将会是一个子部件。Qt::WindowFlags是Qt::WindowType枚举值的组合,用来设置窗口的属性,f = 0表默认为Qt::Widget风格。
Widget(QWidget* parent = nullptr, Qt::WindowFlags f = 0);
自定义窗口类Widget,该类继承自QWidget基类。parent即父窗口,默认为0,即没有父窗口,是顶级窗口。如果指定parent值则当前窗体将会是一个子部件,并且被parent的几何形状所强迫。
Qt::WindowFlags f = 0 (在可用的地方)设置窗口标志;默认值适用于几乎所有窗口组件,但如果要获得一个没有窗口系统框架的窗口,则必须使用特殊的标志。
QWidget有很多成员函数,但是它们中的一些有少量的直接功能:例如,QWidget有一个字体属性,但是它自己从来不用。有很多继承它的子类提供了实际的功能,比如QPushButton、QListBox和QTabDialog等等。
参考连接:
QT部件基类——QWidget与QDialog
【QT】——QWidget窗口类