在构造体内初始化数据成员是最常见的方法。
例如:
#include <iostream> using namespace std; class A { private: int i; string s; public: A(int ii,string ss){ //在构造函数体内初始化数据成员 i=ii; s=ss; cout<<"ctor:i="<<i<<",s="<<s<<endl; } /* 不要写成 A(int i,int j){ i=i;//在这里面,起作用的i是局部域内的i,而不是类的成员i j=j; } //编译虽然不会错,但是你可以运行一下试试 */ void show()const{ cout<<"i="<<i<<",s="<<s<<endl; } }; int main() { A a(5,"str"); a.show(); }
C++还提供了一种叫做构造函数初始化器的方法初始化数据成员。
#include <iostream> using namespace std; class A { private: int i; string s; public: A(int ii,string ss):i(ii),s(ss){ //利用构造函数初始化器初始化数据成员 cout<<"ctor:i="<<i<<",s="<<s<<endl; } /* //利用构造函数初始化器初始化数据成员可以写成这样 //具体原因请看两者的区别 A(int i,string s):i(i),s(s){ cout<<"ctor:i="<<i<<",s="<<s<<endl; } */ void show()const{ cout<<"i="<<i<<",s="<<s<<endl; } }; int main() { A a(7,"构造函数初始化器"); a.show(); }编译以及运行结果为:
构造函数初始化器出现在构造函数参数列表以及构造函数开花括号之间,以冒号开始,逗号分割。
列表中每个元素都使用函数符号或者调用超类构造函数初始化某个数据成员。调用超类构造函数的例子如下:
class B:public A { private: int j; public: B(int i,int j,string s):A(i,s),j(j){ //A(i,s)调用A类中的构造函数 } };
使用构造函数初始化数据成员与在构造函数体内初始化数据成员是不同的。
当C++创建某个对象时,必须在调用构造函数前创建该对象的所有数据成员。如果数据成员本身就是一个对象,那么在创建这些数据成员时,必须为其调用构造函数。当在构造函数体内给某个对象赋值时,并没有真正创建这个对象,而是改变对象的值。
而使用构造函数初始化器则是在创建数据成员的时候赋初值,这样做比前者效率更好。
关于构造函数初始化器要注意的一点是:初始化数据成员的顺序是按照类的定义出现顺序,而不是按照构造函数初始化器中的顺序。
可以做一个简单的测试测试在构造函数体内赋值时的数据成员的初始值情况。
#include <iostream> using namespace std; class A { private: int i; string s; public: A(int ii,string ss){ cout<<"before ctor:i="<<i<<",s="<<s<<endl;//使用构造函数初始化数据成员之前 i=ii; s=ss; cout<<"after ctor:i="<<i<<",s="<<s<<endl;//<span style="font-family: Arial, Helvetica, sans-serif;">使用构造函数初始化数据成员之后</span> } void show()const{ cout<<"i="<<i<<",s="<<s<<endl; } }; int main() { A a(7,"构造函数初始化器"); a.show(); }结果为:
有些人喜欢在构造函数体内初始化数据成员,但是有些数据类型必须在构造函数初始化器中初始化。
1:const数据成员
原因是const成员创建之后无法对其赋值!必须在创建的时候提供初始值。
2.引用数据对象
如果不指向一个量,引用将无法存在
3.没有默认构造函数的对象数据成员
当调用该对象数据成员的默认构造函数初始化成员对象时,无法找到默认构造函数。
4.没有默认构造函数的超类。
类似于3。