我们都知道,C++类成员变量通过构造函数体初始化时,初始化顺序由构造函数体中的变量初始化顺序决定,与类成员变量的定义顺序无关系, 关于如何初始化,巴拉巴拉的我就不多说了,就说大家容易踩的雷区
类成员内部初始化+初始化列表中初始化
在初始化列表中初始化引用对象
为什么我建议使用初始化列表初始化类成员
下面这段代码,你很容易能确定结果:
示例1
#include
using namespace std;
class Sample {
private:
int m_b;
int m_a;
public:
Sample(int i) :m_a(i), m_b(m_a + 1) {
cout
输出结果:10,-858993459 (不同编译器对于m_b的值输出有差异,gcc结果可能是10,32766)
类成员内部初始化+初始化列表中初始化
那我再做个改动,给两个类成员变量在类内部初始化值为0,结果又会是多少呢?
示例2
#include
using namespace std;
class Sample {
private:
int m_b=0;
int m_a=0;
public:
Sample(int i) :m_a(i), m_b(m_a + 1) {
cout
m_a和m_b两个类成员变量的值会是多少呢?
其实输出结果和刚才一样,为什么呢?
C++11类内部初始化,优先于任何构造函数初始化成员变量。内部初始化后,如果构造函数不显式重新初始化成员变量默认值,成员变量将保持内部初始化值默认值;如果构造函数显示重新初始化成员变量默认值,成员变量将保持构造函数重新赋值。
如果初始化列表和构造函数体同时对一个变量进行了初始化,列表初始化会优先得到执行,接着才会执行构造函数体中的变量初始化。
在C++11之前,创建结构体/类只是开辟了一块内存空间,而不赋初始值,赋初始值有的编译器不支持,因此从C++11之后,编译器就支持在结构体/类的定义时进行成员初始化。
在初始化列表中初始化引用对象
引用成员变量我在上一节讲到了,这一节我们再次引申和升华一次,来看这段代码,你觉得会输出什么?
示例3:
#include
using namespace std;
class Sample {
private:
int m_b;
int m_a;
public:
Sample(int i) :m_a(i), m_b(i) {
cout
如果你看走眼了,你以为会输出8,或者4字节的整数倍,可惜这次并不是你想的这样,编译阶段报错了:
/workspace/C1/main.cpp:20:15: error: non-const lvalue reference to type 'Sample' cannot bind to a value of unrelated type 'int'
Test(int i) :m_s(i) {
^ ~
1 error generated.
怎么回事呢?请记住,Sample& m_s是一个引用,而不是指针或变量,因此m_s作为引用成员将引用一个Sample类型的对象,而不是直接构造Sample对象,所以,应该怎么改呢?
我们应该在构造函数的参数里传入一个Sample对象,让m_s引用入参的Sample对象即可。
class Test {
public:
Sample& m_s;
Test(Sample& s) :m_s(s) {
}
};
完整代码如下:
#include
using namespace std;
class Sample {
private:
int m_b;
int m_a;
public:
Sample(int i) :m_a(i), m_b(i) {
cout
为什么我建议使用初始化列表初始化类成员
在学习过程中,经常有人说初始化列表初始化类成员的效率高。是不是这样的呢?
首先我们把类成员变量按类型分类:
1.基本数据类型,复合类型(指针,引用)
2.用户定义类型(类、结构体类型)
分情况说明:
对于1,在成员初始化列表和构造函数体内进行,在性能和结果上都是一样的
对于2,结果上相同,但是性能上存在很大的差别
初始化列表,顾名思义,是对成员数据进行初始化,只需要一次拷贝构造函数即可,而赋值呢,你会发现既要调用其构造函数又要调用赋值运算符重载函数,多了一次操作。
我们来举个例子:
我们先用构造函数体内进行赋值操作
#include
using namespace std;
class Sample {
public:
Sample() { cout
输出结果:
Sample()
construct Test
Sample()
operator=
~Sample()
~Sample()
如果我们使用初始化列表呢,做个对比:
#include
using namespace std;
class Sample {
public:
Sample() { cout
结果:
Sample()
construct Test
copy Sample()
~Sample()
~Sample()
是不是对比下来少了一次函数调用呢。比如游戏服务器在创建十几万甚至几百万的玩家,还有相关活动,战斗副本等数据的时候,使用赋值操作来初始化类成员而不是用参数列表,你可以想象到你需要额外增加多少次函数调用。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net