构造函数的初始化列表
一 首先,先了解构造函数执行分为两个阶段:
1.初始化阶段:
初始化阶段是用构造函数初始化列表方式来初始化类中的数据成员,没有在构造函数的初始化列表中初始化的成员,该成员将在==构造函数体执行之前执行默认初始化==
2.普通计算阶段:
初始化阶段之后,执行构造函数的函数体,函数体内一般是对数据成员的赋值操作
二 构造函数初始化列表语法
类名 (形参列表) : 成员1(形参1),成员2(形参2) …{ }
代码如下:
class student
{
public:
student() = default;//默认构造
student(string Name,int Age):name(Name),age(Age){}//使用初始化列表的有参构造
private:
string name;
int age;
};
三 为啥要使用初始化列表
将上面的构造函数初始化列表改为如下会有什么不同?
student(string Name,int Age)
{
name = Name;
age = Age;
}
对于成员属性是内置的数据类型如,int,char,string,double等,使用初始化列表,和使用普通的赋值语句区别不大,但是对于类类型的成员,使用初始化列表少了一次调用默认构造函数的过程,而是直接调用拷贝构造,这对于数据密集的类类型成员来说是非常高效的
四.有时候初始化列表也是必不可少的
1.在含有常数据成员的类中
2.在含有引用类型的数据成员(因为引用类型创建时必须初始化)
3.没有默认构造函数的类类型成员
因为如果不对类类型的成员使用初始化列表初始化,该成员在初始化阶段会先默认初始化,调用默认构造函数,如果该成员没有默认构造函数就会出问题!
五 成员初始化顺序
初始化列表中按照成员在类中定义的先后顺序来初始化成员,与初始化列表中的顺序无关
来看个例子:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class A
{
public:
A() = default;
A(int a_,int b_): b(b_), a(a_*b) { }
void show();
private:
int a;
int b;
};
void A::show()
{
cout << "a = " << a << endl << "b = " << b << endl;
}
int main()
{
A object(1, 2);
object.show();
return 0;
}
运行结果如下:
说明:可以看到a初始化的结果并不是我们想要的,这是因为a成员在类中定义在b成员的前面,所以初始化列表中先初始化a,执行a(a_ * b) ,而b还未初始化,从而导致a出现乱码。
因此,如果成员初始化依赖其他成员的值,那么要注意初始化顺序,为了避免这个问题,一般按照定义的顺序初始化成员