构造函数初始化列表是一个重要的概念,这一步是构造函数执行时无论如何也要走的一步。构造函数可以说成三部分构成,1)参数列表; 2)初始化列表; 3) 函数体。其中初始化列表是可选的。在一定情况下不需要初始化列表。以下是C++ primer上面的一段代码:
Sales_item::sales_item(const string &book):
isbn(book), units_sold(0), revenue(0.0) {}
初始化列表是指:以冒号开始 并在函数块开始大括号开始前的一段代码,均有数据成员及其初始化参值组成,初始化值在紧随其后的圆括号中。
初始化列表是必须的,在以下情况:
- const 成员
- 引用成员
- 无默认构造函数的类类型成员
解释上面的三种情况之前,先描述下C++ primer上面的几点重要的概念:
- 构造函数分两个阶段进行:初始化阶段、计算阶段。 初始化阶段只初始化列表或者未指定初始化列表,由构造函数隐式初始化的过程。 计算阶段是指执行构造函数函数体里面赋值函数的部分。
- 不管成员是否在构造函数初始化列表中显示的初始化,类类型的数据成员总是在初始化阶段初始化。初始化发生在计算阶段之前。
- 在构造函数函数体(花括号里面的赋值代码)中的代码,仅仅是赋值,而不是初始化!不给定初始化列表初始化,由构造函数隐式的调用默认构造函数初始化。
有了上面三点,就知道了函数体里面只能是赋值,const和引用是不能赋值的,仅在初始化的时候给定初值然后不能改变。因此没有初始化列表是不行的。同理,不给出初始化列表,类类型成员需要初始化,就需要隐式的执行默认构造函数,但是没有默认构造函数,初始化就会失败,这种情况下,只能要初始化列表来进行初始化。
只有初始化列表才能做初始化,构造函数的函数体只是进一步的赋值改变内容而已。
这里顺便回顾下两个概念,初始化和赋值。“=”在某些情况下可以作为赋值,在某些情况下可以作为初始化。
情形1:等号作为初始化
DataType a;//定义类类型变量a,默认构造函数
DataType b = a;//这里等号是初始化
情形2:等号作为赋值
DataType a,b;
a = b;//单纯的赋值
总结起来: 定义的时候等号就是初始化,只有赋值那么等号就只是赋值。
另外两点需要注意的是:
1、内置数据类型,是不会被隐式初始化的,所以在函数体里面和在初始化列表中是没有区别的。
2、初始化列表成员出现的顺序与成员被初始化的顺序无关,只与成员在类中定义的顺序有关。