再谈构造函数
初始化列表
我们可以在函数体内初始化,也可以在构造函数之前初始化列表初始化。
为什么会有初始化列表这个东西呢?我们可以理解对于对象来说,初始化列表是成员变量定义的地方。
class A {
public:
A()
:_c(1)
{}
private:
int _a = 1;//声明
int _b = 2;
//const int _c;
const int _c = 1;//这时候不是初始化,给的是缺省值。
};
int main()
{
A aa;//这里的定义是对象整体的定义,每个成员什么时候定义?
//必须给成员变量找一个定义的位置,不然像const类型的成员不好处理,
return 0;
}
在成员变量中加上const成员变量之后就不能正确运行了,这是因为const变量必须在定义的位置初始化,因为const只有一次初始化的机会。有const成员变量构造函数生不成了,所以要处理const成员变量。const int _c = 1
;//这时候不是初始化,给的是缺省值。 C++11之前怎么处理呢?所以必须给成员变量找一个定义的位置,不然像const类型的成员不好处理。
那成员变量中的缺省值是什么时候用的?缺省值也会在成员变量初始化列表中走。
规定:1.哪个对象调用构造函数,初始化列表是它所有成员变量定义的位置;
2.不管是否显示在初始化列表写,那么编译器每个变量都会在初始化列表定义初始化;当我们在初始化列表显示写的时候,使用初始化列表中的值。
3.有三个变量必须在初始化列表初始化:const变量
,int& 变量名
(引用也必须在定义的地方初始化),没有默认构造的自定义类型成员。每个成员在初始化列表中只能出现一次。
下面_bb
也会初始化,对于自定义类型,会去调用他的默认构造;所以我们不写在初始化列表也会去调用B的构造函数。默认构造是不传参数的,一旦构造函数要传参数就必须在初始化列表中定义。
4.成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。
最好在初始化列表里进行定义,在构造函数体内已经是赋值行为了。能用初始化列表尽量用初始化列表。
class B {
public:
B()
{
cout << "B()" << endl;
}
B(int i)
{
cout << "B()" << endl;
}
private:
int _b = 0;
};
class A {
public:
A()
:_c(1)
, _b(3)
, _ref(_a)
, _bb(0)
{}
private :
int _a;//声明
int _b;
const int _c;
int& _ref;
B _bb;
};
不管写不写初始化列表都会走,是每个成员定义的地方;对于自定义类型,调用默认构造,如果没有默认构造就显示的定义。
下面的代码中我们也可以用A aa1 = 1;
进行初始化,这是一个类型转换
class A {
public :
A(int a)
:_a2(a)
{
}
private:
int _a2;
int _b1;
}
int main()
{
A aa(1);//直接调用构造
A aa1 = 1;
return 0;
}
,int i = 0; double d = i
这句代码发生了隐式类型转换;i不是转换给d,类型转换中间会产生一个临时变量,临时变量还具有常性,i先给临时变量,再给d,临时变量类型是double。那上面的类型转换是如何发生的呢?也是中间会产生临时变量,是A类型,用1去构造一个临时对象,临时对象再去拷贝构造aa2(编译器不优化的情况下)。