在学习QT界面开发的过程中,创建新工程后会遇到如下代码块,涉及C++继承和构造函数的概念,如何更好地理解?
//定义派生类的构造函数
Widget::Widget(QWidget *parent) :
QWidget(parent)//初始化列表 此处parent是实参 把参数交给了父类 然后用父类来进行初始化的
{
}
C++中,子类继承父类除去构造函数和析构函数以外的所有成员。因此,子类需要编写自己的构造函数和析构函数。
需要注意,子类只负责对新增成员进行构造和析构函数编写,父类成员的初始化和清理工作由父类的构造函数和析构函数完成。
无论何种继承方式,子类都无权访问父类的所有成员,所以子类对父类的初始化需要由父类的构造函数完成。此时,子类的构造函数必须提供父类构造函数所需的参数。
子类::子类(全部参数表):父类1(父类1参数表),父类2(父类2参数表)
...对象成员1(对象成员1参数表),对象成员2(对象成员2参数表)
其中,全部参数表包含“所有父类所需参数”和“子类新增成员所需参数”;对象成员表示子类新增的对象成员。
再看底下这个例子:
#include <iostream>
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调用有整型参数的构造函数。
运行后,结果如图所示:
可以看出,
-
创建child1时,是先调用了Base的默认构造函数,再调用自己的默认构造函数;
-
创建child2时,是先调用了Base(int)这个构造函数,再调用自己的整型参数构造函数。
此时,回头看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());
因此,如果不指定构造函数,则派生类会调用基类的默认构造函数。派生类构造函数的初始化列表只能初始化派生类成员,不能直接初始化继承成员,如果想要调用基类的有参构造函数,则可以在派生类的初始化列表中显式指定。