《C++ Primer Plus》中的成员初始化列表

对于构造函数Queue::Queue(int qs):

Queue::Queue(int qs)
{
    front = NULL;
rear = NULL; items
= 0; qsize = qs; }

当qsize为常量(即const int qsize)时,上述实现无法正常运行。因为调用构造函数时,对象将在大括号中的代码执行之前被创建,亦即构造函数将先为4个成员变量分配内存,然后,程序进入到大括号中使用常规的赋值方法将值存储到内存中。对于const数据成员,必须在执行到构造函数体之前,也就是创建对象时进行初始化。通过成员初始化列表,可以实现上述工作。

成员初始化列表由逗号分割的初始化列表组成(前面带冒号),位于构造函数的参数列表之后,函数体括号之前。如果数据成员名称为mdata,且需要初始化为val,则初始化器为mdata(val),在此,初始化与赋值的区别再次体现出来。上述Queue类的构造函数以成员初始化列表语法表示如下:

Queue::Queue(int qs) : qsize(qs), front(NULL), rear(NULL), items(0)
{
}

对于const类成员以及被声明为引用的类成员,必须使用这种语法。这是因为引用与const数据类似,只能在被创建时进行初始化。对于简单数据成员,使用成员初始化列表和在函数体中使用赋值没有什么区别,而对于本身就是类对象的成员来说,使用成员初始化列表的效率更高,因为在构造函数体中赋值需要首先调用类对象成员的默认构造函数,然后在调用赋值运算符对其进行赋值,而成员初始化列表语法可以减少一个步骤,直接使用类对象成员的复制构造函数进行初始化。

数据成员被初始化的顺序与它们出现在类声明中的顺序相同,与初始化器中的排列顺序无关。

需要注意的是,不能将成员初始化列表语法用于构造函数之外的其他类方法。

派生类不能直接访问基类的私有成员,而必须通过基类方法进行访问,因此,派生类构造函数必须使用基类构造函数。

创建派生类对象时,程序首先创建基类对象,这意味着基类对象应当在程序进入派生类构造函数之前被创建,因此需要成员初始化列表语法,而派生类成员使用成员初始化列表语法与否均可。

RatedPlayer::RatedPlayer(unsigned int r, const string & fn, const string & ln, bool ht) : TableTennisPlayer(fn, ln, ht)
{
    rating = r;
}

RatedPlayer::RatedPlayer(unsigned int r, const TableTennisPlayer & tp) : TableTennisPlayer(tp)
{
    rating = r;
}

上述代码中,第一个构造函数调用基类的构造函数(需要用初始化列表语法指明使用的基类构造函数,否则将调用默认构造函数),第二个构造函数调用基类的复制构造函数。

总之,在派生类构造函数中,首先创建基类对象,然后通过成员初始化列表将基类信息传递给基类构造函数,此外,还要对派生类新增的数据成员进行初始化。而派生类对象过期时,程序将首先调用派生类析构函数,然后再调用基类析构函数。

注:

成员初始化列表与在默认构造函数中对数据成员赋值的区别在于,如果没有成员初始化列表,则数据成员将在构造函数体之前执行默认初始化,而成员初始化列表随着构造函数体一开始执行,初始化就完成了,对于无法先定义后赋值的const或者引用类型的数据,以及属于某种未提供默认构造函数的类类型,必须通过构造函数初始值列表为这些成员提供初始值。

除此之外,由于数据成员被初始化的顺序与它们出现在类声明中的顺序相同,与初始化器中的排列顺序无关,因此最好使构造函数成员初始化列表的顺序与成员声明顺序一致,况且在允许的情况下,尽量避免使用某些成员初始化其他成员。

posted @ 2021-08-17 13:41  溪嘉嘉  阅读(147)  评论(0编辑  收藏  举报