构造函数的成员初始化列表问题

必须在派生类构造函数中初始化的几种情况

派生类构造函数对基类初始化

  • 基类没有显式声明构造函数或者有一个无参数的构造函数,派生类构造函数可以不用对基类初始化,即忽略基类的构造函数,
  • 基类的构造函数全是有参数的,派生类必须至少实现一个基类的构造函数,例如Qt中常见的:
explicit MainWindow(QWidget* parent=0);
//QMainWindow构造函数都有参数
MainWindow::Mainwindow(QWidget* parent):
    QMainWindow(parent),
    ui(new Ui::MainWindow)

这种方式解决的问题是:使用派生类创建一个对象后,怎样初始化从基类中继承过来的数据成员?(基类的构造函数是不能被继承的)

这种代码的具体格式:

派生类::派生类构造函数(总参数列表):基类构造函数(参数列表)
{
    派生类中的数据成员初始化;
}

注意:如果没有基类和派生的关系,就不能用这种初始化格式,否则报错。

类中的const成员进行初始化必须用这种方式

class Father {
public:
    explicit Father(int father):
            f(father),
            m(10)
    {

    }
private:
    const int f;
    const int m;
};

如果不用这种方式初始化,会编译报错:error: C2789:必须初始化常量限定类型的对象

两个类没有继承关系,但是一个类A包含类B的成员变量,而后者的构造函数都是有参数的,此时必须在类A构造函数中对B初始化

举例:Father类跟上面一样,增加类MyClass如下:

class MyClass
{
public:
    explicit MyClass()
       :father(s)
    {

    }
private:
    Father father;
    int s;
};

MyClass构造函数前,先运行Father的构造函数,所以需要对其初始化,否则报错。这里实际上用到了类的隐式转换。
只要Father类有一个函数是无参数的,那就不需要在MyClass类中对father显式初始化,让编译器自动完成即可。

如果嫌初始化太麻烦,就可以把father改成指针类型,这也是Qt中的常见方法,然后可以到MyClass的构造函数中对指针进行初始化,也可以仍然用成员初始化列表的方法:

class MyClass
{
public:
    explicit MyClass()
       :father(new Father(s))
    {

    }
private:
    Father father;
    int s;
};

类似的,Qt中的ui变量初始化可以放到构造函数里:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    ui = new Ui::MainWindow;
    ui->setupUi(this);
}

构造函数中初始化的顺序

初始化的顺序与列表中的顺序无关,而是由类中定义的先后顺序决定。

Base::Base(int a)
{
    std::cout<<"constructor Base:"<<a<<endl;
}

class Derive : public Base
{
public:
    Derive();
    Base a;
    Base b;
};
Derive::Derive():
    b(8),
    a(4)
{
}

Derive* d = new Derive();

运行结果是

constructor Base:4  //先a后b
constructor Base:8

与初始化时a和b的顺序无关,只跟类Derive中的声明顺序有关。

静态变量不能用构造函数成员列表初始化

静态变量不属于某个对象,而是被类共有,假如构造函数能初始化,会造成变量值不同。编译时报错:error: C2438 无法通过构造函数初始化静态类数据

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页