Foo(int num): bar(num)
这个构造在c++中称为成员初始化器列表。
简单地说,它将你的成员栏初始化为值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没有默认构造函数,因此需要使用成员初始化列表来初始化它的成员。
在使用成员初始化列表时需要注意的要点:
类成员变量总是按照它们在类中声明的顺序进行初始化。
它们没有按照在成员初始化列表中指定的顺序进行初始化。
简而言之,成员初始化列表并不决定初始化的顺序。
综上所述,保持与类定义中声明成员的顺序相同的成员初始化顺序始终是一种良好的实践。这是因为编译器不会在两个顺序不同时发出警告,但相对较新的用户可能会将成员Initializer列表误认为初始化顺序,并据此编写一些代码。