Foo(int num): bar(num)
在C++中,这个结构称为成员初始化列表。
简单地说,它将您的成员bar
初始化为一个值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:
int &i;
int b;
const int k;
MyClass(int a, int b, int c) : i(a), b(b), k(c) {
}
};
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 initialization列表中成员的顺序与其在类定义中声明的顺序保持一致是一个良好的实践。这是因为编译器不会发出警告,如果两个顺序不同,那么一个相对较新的用户可能会将Member Initializer list与初始化顺序混淆,并编写一些依赖于此的代码。
const
成员变量或引用,就必须使用初始化列表。 - Charles Salvia