class A { public: A(int n){ cout << "A ..." << endl; } ~A(){} }; class B { public: B(int n){ cout << "B ..." << endl; } ~B(){} }; class MyClass { public: MyClass(); ~MyClass(){} private: B m_b; A m_a; int m; string m_str; int n; }; MyClass::MyClass():m_a(1),m_b(2) { n = 100; m = 99; m_str = "138182"; cout << "MyClass ..." << endl; }
说明:成员被初始化的顺序,与初始化列表里面的顺序没有关系,只和成员的声明顺序有关。先声明的,先初始化。
class A { public: A(){ cout << "A ...000" << endl; } A(int n){ cout << "A ...111" << endl; } // A(A& a){} ~A(){} }; class B { public: B(){ cout << "B ...000" << endl; } B(int n){ cout << "B ...111" << endl; } // B(B& b){} ~B(){} }; class MyClass { public: MyClass(); ~MyClass(){} private: B m_b; A m_a; int m; string m_str; }; MyClass::MyClass() { cout << "MyClass ..." << endl; m = 99; m_str = "138182"; m_a = 1; m_b = 2; }
1.内置数据类型,复合类型(指针,引用)
在成员初始化列表中初始化,和在构造函数体内赋值,性能和结果完全一样。
2.用户定义类型(类类型)
结果上相同,但是性能上存在很大的差别。因为类类型的数据成员对象在进入函数体前已经构造完成,也就是说在成员初始化列表处进行构造对象的工作,调用构造函数,在进入函数体之后,进行的是对已经构造好的类对象的赋值,又调用个拷贝赋值操作符才能完成(如果并未提供,则使用编译器提供的默认按成员赋值行为)
总结:
1、初始化列表中的初始化顺序,至于类成员的声明顺序有关,直接调用构造函数进行初始化;
2、在类的构造函数中对类成员进行赋值,这些成员对象在进入函数体之前要先完成构造,必须得有合适的构造函数可用(无参数的构造函数,或有默认参数的构造函数);
进入函数体之后,再对已经构造好的类对象进行赋值,要调用构造函数,再调用赋值运算符(有默认赋值运算符)