Foo(int num): bar(num)
此构造在 C++ 中称为 成员初始化器列表。
简单地说,它初始化您的成员 bar
为值 num
。
构造函数内部的初始化和赋值有什么区别?
成员初始化:
Foo(int num): bar(num) {};
成员分配:
Foo(int num)
{
bar = num;
}
使用成员初始化器列表初始化成员与在构造函数主体内为其分配值之间存在显着差异。
当您通过成员初始化列表初始化字段时,构造函数将被调用一次,并且对象将在一次操作中构造和初始化。
如果您使用 assignment,则字段将首先使用默认构造函数进行初始化,然后使用实际值重新分配(通过赋值运算符)。
如您所见,后者有额外的创建和分配开销,这对于用户定义的类来说可能是相当大的。
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 类成员,没有实际开销。
什么时候必须使用成员初始化器列表?
如果出现以下情况,您将(相当被迫)使用成员初始化器列表:
- 您的类(class)有一个引用成员
- 您的类有一个非静态 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 列表混淆为初始化顺序并编写一些依赖于此的代码。
我是一名优秀的程序员,十分优秀!