构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每一个数据成员后面跟一个放在括号中的初始化式。例如:函数
class A { public: int a; float b; A(): a(0),b(9.9) {} //构造函数初始化列表 }; class A { public: int a; float b; A() //构造函数内部赋值 { a = 0; b = 9.9; } };
上面的例子中两个构造函数的效果是同样的。使用初始化列表的构造函数是显示地初始化类的成员;而没有使用初始化列表的构造函数是对类的成员赋值,并无显示地初始化。spa
初始化列表的构造函数和内部赋值的构造函数对内置类型的成员没有什么大的区别,像上面的任一个构造函数均可以。
用构造函数的初始化列表来进行初始化,写法方便、简练,尤为当须要初始化的数据成员较多时更显其优越性。对非内置类型成员变量,推荐使用类构造函数初始化列表。
但有的时候必须用带有初始化列表的构造函数:(1)没有默认构造函数的成员类对象;(2)const成员或引用类型的成员。 code
构造函数中有着比咱们所看见的还要多的细节,构造函数能够调用其它的构造函数来初始化对象中的基类对象和成员对象的构造函数。
类的数据成员中的其它类对象,若该成员类型是没有默认构造函数,则必须进行显示初始化,由于编译器会隐式调用成员类型的默认构造函数,而它又没有默认构造函数,则编译器尝试使用默认构造函数将会失败。
对象
例:blog
class A { public: A (int x) { i = x; // 无默认构造函数 } private: int i; }; class B { public: B(int y) { j = y; // error C2512: “A”: 没有合适的默认构造函数可用 } private: A a; int j; }; int main( ) { B b(5); return 0; }
B类数据成员中有一个A类对象a,建立B类对象时,要先建立其成员对象a;A类有一个参数化大的构造函数,则编译器不会提供默认无参数的构造函数,所以a没法建立。编译器
对成员对象正确的初始化方法是经过显示方式进行,B的构造函数应该写成:string
B(int y, int z) : a(z) { j = y; } B b(5,10);
构造函数初始化列表是初始化常数据成员和引用成员的惟一方式。由于const对象或引用类型只能初始化,不能对他们赋值。
编译
class A { public: A (int x,int y) : c(x),j(y) // 构造函数初始化列表 { i = -1; } private: int i; const int c; int& j; }; int main( ) { int m; A a(5,m); return 0; }
若不经过初始化列表来对常数据成员和引用成员进行初始化:class
class A { public: A (int x) // 构造函数初始化列表 { i = -1; c = 5; j = x; } private: int i; const int c; // error C2758: “A::c”: 必须在构造函数基/成员初始值设定项列表中初始化 int& j; // error C2758: “A::j”: 必须在构造函数基/成员初始值设定项列表中初始化 };
缺省状况下,在构造函数的被执行前,对象中的全部成员都已经被它们的缺省构造函数初始化了。当类中某个数据成员自己也是一个类对象时,咱们应该避免使用赋值操做来对该成员进行初始化:效率
class Person { private: string name; public: Person(string& n) { name = n; } }
虽然这样的构造函数也能达到正确的结果,但这样写效率并不高。当一个Person对象建立时,string类成员对象name先会被缺省构造函数进行初始化,而后在Person类构造函数中,它的值又会因赋值操做而在改变一次。咱们能够经过初始化列表来显示地对name进行初始化,这样便将上边的两步(初始化和赋值)合并到一个步骤中了。
class Person { private: string name; public: Person(string& n): name(n){} }