8.5.5 初始化表达式

    除了在构造函数体内初始化数据成员外,还可以通过成员初始化表达式来完成。成员初始化表达式可用于初始化类的任意数据成员(后面要介绍的static数据成员除外),该表达式由逗号分隔的数据成员组成,初值放在一对圆括号中。只要将成员初始化表达式放在构造函数的头和体之间,并用冒号将其与构造函数的头分隔开,便可实现数据成员表达式中元素的初始化,对代码8-6而言有下述等价代码。


    point(int x,int y) { cout<<"有参构造函数的调用"<<endl; xPos=x; yPos=y; }等价于 point(int x,int y):xPos(x),yPos(y) { cout<<"有参构造函数的调用"<<endl; }

    “xPos(x),yPos(y)”即是成员初始化表达式,用成员初始化表达式初始化类成员与用构造函数初始化类成员的区别在于:前者的初始化是在构造函数体被执行以前进行的。对普通类型的变量来说,采用构造函数体内赋值初始化和成员初始化表达式进行初始化几乎是等价的,但对一些特殊的数据成员,两种初始化方式会有一定的差异。

    注意

    由成员初始化表达式可以看,C++内建的数据类型,如int和double等也可以看做一种类,通过该类声明的变量即是该类型的对象。

    每个成员在成员初始化表中只能出现一次,初始化的顺序不是由名字在初始化表中的顺序来决定的,而是由成员在类中被声明的顺序决定的。理解这一问题有助于避免意想不到的错误发生,如代码8.7所示。

    代码8.7 成员初始化表顺序Constructor3


    <—————————————-文件名:point.h—————————————————> 01 #include<iostream> 02 using namespace std; 03 class point 04 { 05 private: 06 int yPos; 07 int xPos; 08 public: 09 point(int x):xPos(x),yPos(xPos)//初始化表取决于成员声明的顺序 10 { 11 } 12 void print() 13 { 14 cout<<"xPos:"<<xPos<<",yPos:"<<yPos<<endl; 15 } 16 }; <————————————文件名:example807.cpp———————————————> 17 #include"point.h" 18 int main() 19 { 20 point pt1(3);//调用有参构造函数声明变量pt1 21 pt1. print(); 22 return 0; 23 }

    输出结果如下所示。


    xPos:3,yPos:-858993460

    【代码解析】从代码8.7的输出结果看,yPos并没有像预想的那样被初始化为3,问题出在代码第9行的语句上,从成员初始化表的字面顺序看,xPos用x初始化,yPos用xPos初始化,似乎并没有问题。实际上,成员初始化的顺序取决于成员在类定义中的顺序,yPos排在xPos前,因此,“yPos(xPos)”先被执行,xPos(x)后被执行,这意味着yPos的值取决于xPos内存开辟成功后的值,并不等于x。

    技巧如果可能(一些变量只能在初始化表中进行初始化,稍后会有介绍),将类似于代码8.7中yPos这样的成员放在构造函数体内初始化。