类和对象的深入了解6
1.初始化列表
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括 号中的初始值或表达式。
class Date
{
public:Date(int year, int month, int day): _year(year), _month(month), _day(day){}private:int _year;int _month;int _day;
};
注意:
1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次,但是构造函数可以多次调用)。
2. 类中包含以下成员,必须放在初始化列表位置进行初始化(其余的可以放入,也可以放入构造函数内):
1. 引用成员变量
2.const成员变量
3.自定义类型成员(且该类没有默认构造函数时)。
class A
{
public:A(int a):_a(a){}
private:int _a;
};
class B
{
public:B(int a, int ref):_aobj(a),_ref(ref),_n(10){}
private:A _aobj; // 没有默认构造函数int& _ref; // 引用const int _n; // const
};
3.尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使 用初始化列表初始化。
4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。
class A
{
public:A(int a):_a1(a),_a2(_a1){}void Print() {cout<<_a1<<" "<<_a2<<endl;}
private:int _a2;int _a1;
};
int main() {A aa(1);aa.Print();
}
上述代码运行结果是什么呢?
A. 输出1 1 B.程序崩溃 C.编译不通过 D.输出1 随机值
答案为D
上述规则中我们知道初始化列表会先执行声明的成员变量,我们可以看到类中先声明的成员变量为_a2,然后为_a1,这样的话在初始化列表中先初始化_a2,但是给_a2的初始化值为_a1,但是此时的_a1还未初始化,所以_a2为随机值,_a1为a。
2.explicit关键字
构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函 数,还具有类型转换的作用。
上述代码中存在一个只需要传一个int 类型参数的构造函数,正是这一点我们可以写出下面的隐式类型转换,我们写的A b1 =2,意思其实是提供一个2给构造函数,创建一个临时的对象吗,然后再拷贝构造给b1对象(当然,如果是多个形参也可以,只是需要用花括号括起来)。
那么这里与explicit有何关系呢?
我们只需要在对应的构造函数前加上该关键字,就可以让其不发生隐式类型转换。