这是我在阅读Effective c++中认为比较重要的部分,下面给出了我对这一节的理解,并写出对应的比较容易理解的代码。
重要的的类中的构造函数是赋值而不是初始化,对于类类型name,则是先初始化再赋值,对于内置类型nums,编译器不保证会初始化。
class A {
A(string&name, int nums) {
name = name;
nums = nums;
}
private:
string name;
int nums;
};
比起先调用默认构造再调用拷贝赋值,只调用一次拷贝构造是比较高效的,实现方法是指定成员初值列,如下:
class A {
A(string&name, int nums):name(name),nums(nums) {}
private:
string name;
int nums;
};
如果成员变量是const或reference,它们就一定要先初始化,然后才能赋值。
static对象其寿命从被构造出来直到程序结束为止,这种对象包括global对象、定义于namespace作用域的对象、在class内,函数内以及file作用域内被声明为static的对象。
在函数内的static对象被称为local-static对象,其余为non-local static对象。
c++对定义于不同的编译单元内的non-local static对象的初始化次序无明确定义。
例如:
文件1:
class A {
public:
A();
int jk = 5;
int get();
};
extern A a;
class B {
public :
int mm = 10;
int get();
}bb;
int B::get() {
return a.jk;
}
文件2:
class B {
public:
int m = 10;
int get();
};
class A{
public:
A() {}
int jk = 5;
int get() {
return jk;
}
}a;
int main() {
B bb;
cout << bb.get();
}
B中的get需要用到A的对象a,但不确定对象b和对象a谁先初始化,可能导致错误。
解决方法是以local对象替换non-local static对象。以函数调用返回函数内的static 对象的引用,此对象会在被调用时被初始化。
所以修改以上代码如下:
A.h:
class A {
public:
A(){}
int jk = 5;
int get();
};
B.h:
class B {
public:
int m = 10;
int get();
};
b.cpp:
#include"A.h"
#include"B.h"
A& tfs() {
static A a;
return a;
}
int B::get() {
return tfs().get();
}
源文件.cpp:
#include"A.h"
#include"B.h"
using namespace std;
int A::get() {
return jk;
}
int main() {
B b;
cout << b.get();
}
请记住
为内置型对象进行手工初始化,因为C++不保证初始化它们。
构造函数最好使用成员初值列,而不要再构造函数本体内使用赋值操作。初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同。
为免除“跨编译单元之初始化次序”问题,请以local static对象替换 non-local static对象