Foo(int num): bar(num)
此构造在 C++中称为成员初始值设定项列表。
简单地说,它将您的成员初始化bar
为 value num
。
构造函数中的初始化和赋值有什么区别?
成员初始化:
Foo(int num): bar(num) {};
成员分配:
Foo(int num)
{
bar = num;
}
使用成员初始化器列表初始化成员和在构造函数主体内为其分配值之间存在显着差异。
当您通过成员初始化器列表初始化字段时,将调用一次构造函数,并且将在一次操作中构造和初始化对象。
如果您使用赋值,则字段将首先使用默认构造函数初始化,然后使用实际值重新分配(通过赋值运算符)。
如您所见,后者有额外的创建和分配开销,这对于用户定义的类可能相当大。
Cost of Member Initialization = Object Construction
Cost of Member Assignment = Object Construction + Assignment
后者实际上等价于:
Foo(int num) : bar() {bar = num;}
而前者相当于:
Foo(int num): bar(num){}
对于内置(您的代码示例)或 POD 类成员,没有实际开销。
什么时候必须使用成员初始化器列表?
如果出现以下情况,您将不得不(相当被迫)使用成员初始化器列表:
- 你的班级有一个参考成员
- 您的班级有一个非静态 const 成员或
- 您的类成员没有默认构造函数或
- 用于基类成员的初始化或
- 当构造函数的参数名称与数据成员相同时(这不是必须的)
代码示例:
class MyClass {
public:
// Reference member, has to be Initialized in Member Initializer List
int &i;
int b;
// Non static const member, must be Initialized in Member Initializer List
const int k;
// Constructor’s parameter name b is same as class data member
// Other way is to use this->b to refer to data member
MyClass(int a, int b, int c) : i(a), b(b), k(c) {
// Without Member Initializer
// this->b = b;
}
};
class MyClass2 : public MyClass {
public:
int p;
int q;
MyClass2(int x, int y, int z, int l, int m) : MyClass(x, y, z), p(l), q(m) {}
};
int main() {
int x = 10;
int y = 20;
int z = 30;
MyClass obj(x, y, z);
int l = 40;
int m = 50;
MyClass2 obj2(x, y, z, l, m);
return 0;
}
MyClass2
没有默认构造函数,因此必须通过成员初始化器列表进行初始化。
- 基类
MyClass
没有默认构造函数,因此要初始化其成员,需要使用成员初始化器列表。
使用成员初始化器列表时需要注意的要点:
类成员变量总是按照它们在类中声明的顺序进行初始化。
它们没有按照在成员初始化器列表中指定的顺序进行初始化。
简而言之,Member 初始化列表不决定初始化的顺序。
鉴于上述情况,保持成员初始化的成员顺序与在类定义中声明它们的顺序相同始终是一个好习惯。这是因为如果两个顺序不同,编译器不会发出警告,但是相对较新的用户可能会将成员 Initializer 列表混淆为初始化顺序并编写一些依赖于此的代码。