在C++开发中经常会使用成员变量,有时候会看到既存代码中,在构造函数对内置类型的成员变量进行赋值操作,而没有使用成员初始列。有的甚至没有初始过成员变量,声明之后就直接使用了。
有的人可能认为内置类型会被自动初始化,所以认为没必要,但是这个可能在某些平台开发时不会自动初始化,因此最好手动初始化所有成员,通常编程规范中也会有这种要求。
下面主要区分一下赋值和初始化:
例:
class ABEntry {
public:
ABEntry(const std::string& name, const std::string&address);
private:
std::string theName;
std::string theAddress;
};
ABEntry::ABEntry(const std::string& name, const std::string&address) {
theName = name; // 这些是赋值
theAddress = address; // 不是初始化
}
上述这种方法虽然也能实现给对象你所期望的值,但这不是最佳做法。
C++规定,对象成员变量初始化动作发生在进入构造函数本体之前。上述成员变量都是被赋值。初始化发生的时间更早,发生于这些成员的default构造函数被自动调用之时(比进入ABEntry构造函数本体的时间更早)。
所以最佳写法:
ABEntry::ABEntry(const std::string& name, const std::string&address)
:theName(name)
,theAddress(address)
{
// 构造函数中不需要其它任何动作
}
这个构造函数和上一个的最终结果相同,但通常效率较高。上述例子第一个方法,首先调用default构造函数为成员变量设初值,然后再立刻对它们赋值。default构造函数一切作为因此浪费了。
第二种方法就避免了这一问题。
对大多数类型而言,比起先调用default构造函数然后再调用copy assignment操作符,单只调用一次copy构造函数是比较高效的,有时甚至高效得多。
初始化成员变量时注意顺序,class的成员变量总是以其声明次序被初始化。有时候成员变量初始化存在依赖关系,比如数组初始化时需要指定大小,因此代表大小的那个成员变量必须先有初值。
有时候会遇到跨编译单元(两个不同文件成员变量)初始化时问题,这时候使用的技术是将每个non-local-static对象搬到自己的专属函数内(该对象在此函数内被声明为static)。这些函数返回一个reference指向它所含的对象。然后用户调研这些函数,而不直接指涉这些对象。
请记住
- 为内置型对象进行手工初始化,因为C++不保证初始化它们。
- 构造函数最好使用成员初始列,而不要在构造函数本体内使用赋值操作。初始列列出的成员变量,其排列次序应该和它们在class中的声明次序相同。
- 为免除“跨编译单元初始化次序”问题,请以local static对象替换non-local static对象。
在实际项目开发中通常项目编程规范都会明确提出成员变量初始化条款,所以平时开发过程中也需要注意这些细节问题,避免遇到成员变量初始化错误的情况。