C++为什么需要成员初始化列表

来源:互联网 发布:软件导刊录用率高吗 编辑:程序博客网 时间:2024/06/07 09:53

将构造函数分为两个阶段的执行过程:初始化阶段和构造函数函数体阶段。

既然称它为成员初始化列表,那么该阶段在初始化阶段完成。

那么类成员变量不外乎类类型和非类类型。而对于非类类型而言,此时

无论是在初始化表中还是函数体内完成赋值效果是一致的,即并未初始化。

表现的有点不同的是类类型:

test1:

#include<iostream>using namespace std;class B{public:B(){cout<<"B()"<<endl;}B(int i){cout<<"B(int i)"<<endl;}};class A{public:A(){cout<<"A()"<<endl;}private:B b;};int main(){A a;return 0;}


B类的默认构造函数被调用来初始化 b 对象了,也就是说对于类类型对象将调用它的默认构造函数完成初始化。

如果在成员初始化列表中显示地用B类接收int 形参的构造函数会怎么样:

test2:

#include<iostream>using namespace std;class B{public:B(){cout<<"B()"<<endl;}B(int i){cout<<"B("<<i<<")"<<endl;}};class A{public:A():b(12345){cout<<"A()"<<endl;}private:B b;};int main(){A a;return 0;}


B成员的对象直接调用了带int形参的构造函数,利用成员初始化列表我们完成了类成员的初始化工作。

那如果将他放入函数体中呢:

test3:

#include<iostream>using namespace std;class B{public:B(){cout<<"B()"<<endl;}B(int i){cout<<"B("<<i<<")"<<endl;}};class A{public:A(){b=12345;cout<<"A()"<<endl;}private:B b;};int main(){A a;return 0;}


可以看见,它同样可以达到想要的结果,可是此时我们期望的是利用带参数的构造函数初始化B类对象,并不期望多此一举的

先调用默认构造。而之所以这样就是因为我们并未将初始化在函数体之前完成,而是将它带入了函数体。

所以,对于类类型对象的成员变量初始化过程:

1 编译器发现有类对象的定义时,首先找到了成员初始化列表,如果未找到相应的初始化定义,

则调用类的默认构造函数来完成初始化。找到则采用列表中的定义。

2 如果用户希望采取非默认构造初始化对象,而有将其放在函数体中,则此时一定要为该类提供默认的

构造函数,否则编译报错。

3 可以看出,如果你显示定义了带参构造,那么总是为类提供一个默认的构造函数是好的习惯,可以帮你避免许多可能麻烦。

4 对于某些必须在定义的同时初始化的变量,成员初始化列表就是非用不可的了,如const或则是引用类型,否则编译报错。

5 注意上面所说的是类类型成员对象的表现,而非引用或指针的表现。

特殊的成员:static成员它是在什么时候初始化的呢?答案是在第一次用到该成员时,因为static成员在内存中只有一份的拷贝,

它在整个程序阶段只被初始化一次。可以往A中加入static变量定义,发现实例化A对象后static变量未被初始化。


总之。如何利用好成员的初始化列表还是很重要的。



原创粉丝点击