成员初始化列表的使用及特点

成员初始化列表:用于辅佐构造函数(可以是默认构造函数),对成员变量进行赋值。

一般情况下,使用成员初始化列表与在构造函数内部对成员进行赋值没有什么好坏之分,使用哪种方式对对象进行初始化全凭心情。

但是,在以下四种情况的成员变量中,只能使用成员初始化列表进行初始化:

1.当初始化一个const member时。这种情况不用多说,对于const变量的初始化只能使用初始化列表,而不能在constructor中进行赋值,不然违背成员变量const的性质。

2.当初始化一个reference member时。平常对于引用的研究比较少,等看完手头的书专门看下引用。这里因为成员变量的属性为引用类型,代表这个成员变量将是另一个变量的别名,他们不仅仅是值相等,其实更是互相等价。因为在使用的时候,必须要先初始化在赋值,也就是说,必须要int& c=a;后才可以c=100;而如果不在成员初始化列表中先初始化,是不可以在constructor中直接赋值的。

3.调用一个base class的constructor,而它拥有一组参数时。

4.调用一个member class的constructor,而它拥有一组参数时。

3与4其实是很相近的,它们都是因为需要使用的调用的constructor中本来就需要用成员初始化列表进行初始化。

讲完了使用,下面看下成员初始化列表的特点

首先是当使用了成员初始化列表后,整个构造函数的运行顺序:

实际上,编译器会对成员初始化列表进行操作,将它们安插在constructor之中,但这是有一个先后顺序的:

一定是优先进行成员初始化列表中的操作,然后在进行原本设计在constructor中的操作。

其次,在成员初始化列表的操作中,一定是按照声明先后顺序进行初始化!

在以下情况:

class A

{

  int a;

  int b;

  A(int val):b(val),a(b)

  {

  }

}

看似好像是先用val初始化b,然后用b初始化a。但实际上,按照声明的先后顺序,应该优先进行的是a(b),而此时b是个不知道为多少的鬼值,因此a也被初始化为一个鬼,在进行b=val。

因此,在成员初始化列表中初始化时,当出现用类中成员去初始化另一个成员时,一定要注意声明先后顺序。而在constructor中进行初始化则不用考虑这些,因为constructor中一定是按照你赋值语句的顺序进行的。

另外,在设计到基类成员时,也会涉及到先后顺序的问题:

class FooBar:public X{

  int _fval;

public:

  int fval(){return _fval;}

  FooBar(int val):_fval(val),X(fval())

  {}

}

从语意上来说,好像是想用val初始化派生类的成员_fval,在用派生类成员_fval去初始化基类的成员。

然而,在内存布局上,基类的成员是先于派生类声明的,因此实际上达到的效果为:

FooBar::FooBar(this,int val)

{

  X::X(this,this->fval);

  _fval=val;

}

这个顺序恰好与所想的相反,基类被初始化为一堆不知道是多少的数后才开始初始化派生类的_fval成员。

原文地址:https://www.cnblogs.com/lxy-xf/p/11049863.html