1 初始化列表
初始化列表:以一个 冒号开始 ,接着是一个以 逗号分隔的数据成员列表 ,每个 " 成员变量 " 后面跟一个 放在括号中的初始值或表达式。
例如:我们Date类用初始化列表初始化如下
class Date
{
public:
//初始化列表
Date(int year = 1, int month = 1, int day = 1)
:_year(year)
,_month(month)
,_day(day)
{
}
private:
//声明
int _year;
int _month;
int _day;
};
int main()
{
//对象
Date d1(2022, 5, 22);
Date d2;
return 0;
}
1.1为什么要用初始化列表
初始化列表是对象成员定义的地方,而有些成员必须在定义的地方初始化。
必须在定义时初始化的变量:
(a) 引用成员变量 (b)const成员变量 (c)自定义类型(无默认构造函数)
class A
{
public:
A(int a)
:_a(a)
{
}
private:
int _a;
};
class Date
{
public:
//对象成员定义的地方
Date(int year, int n, int ref,int a)
:_n(n)
,_ref(ref)
,_aa(a)
{
_year = year;
}
private:
//以下区域属于声明,不属于定义
//可以在定义时初始化;也可以定义时不初始化,后面再赋值修改
int _year;
//只能在定义的时候初始化
const int _n;
int& _ref;
A _aa;
};
注意:
- 每个成员变量在初始化列表中 只能出现一次 ( 初始化只能初始化一次 )
- 类中包含以下成员,必须放在初始化列表位置进行初始化:
(a)引用成员变量
(b)const 成员变量
(c)自定义类型成员 ( 该类没有默认构造函数 ) - 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
- 成员变量 在类中声明次序就是其在初始化列表中的初始化顺序 ,与其在初始化列表中的先后次序无关。
1.2C++11 的成员初始化新玩法。
C++11 支持非静态成员变量在声明时进行初始化赋值, 但是要注意这里不是初始化,这里是给声明的成员变量 缺省值 。
class B
{
public:
B(int b = 0)
:_b(b)
{
}
private:
int _b;
};
class A
{
public:
private:
//非静态成员变量,可以在成员声明时给缺省值
int a = 10;
B b = 20;//隐士类型转换
int* p = (int*)malloc(4);
};
注意:静态成员不能在此赋值,因为静态成员不会在初始化列表初始化。
2 explicit关键字
构造函数不仅可以构造与初始化对象,对于单个参数的构造函数,还具有类型转换的作用。
class Date
{
public:
Date(int year)
:_year(year)
{
cout << "Date(int year)" << endl;
}
Date(const Date& d)
{
cout << "Date(const Date& d)" << endl;
}
private:
int _year;
};
int main()
{
Date d1(2022);//构造
//隐士类型的抓换
Date d2 = 2022;//构造+拷贝构造 -》优化
return 0;
}
我们可以发现2022是int类型,而d2是Date类型,因此这里发生了隐式转换。如果不想发生类型转换在构造函数前加上explicit即可。
class Date
{
public:
explicit Date(int year)
:_year(year)
{
cout << "Date(int year)" << endl;
}
private:
int _year;
};
int main()
{
Date d1(2022);//构造
//隐士类型的抓换
Date d2 = 2022;//构造+拷贝构造 -》优化
return 0;
}
此时就会发生错误:
上述代码可读性不是很好,用explicit修饰构造函数,将会禁止单参构造函数的隐式转换。