C++编程语言应用范围非常广泛,而且应用方式灵活,在一定程度上提高了编程人员的开发效率。那么接下来,我们就可以通过以下对C++初始化列表的相关实现方法的掌握,来初步了解这一语言的应用技巧。
先看下面这段程序
- #include < iostream>
- #include < vector>
- using namespace std;
- class array
- {
- public:
- array(int lowbound, int highbound);
- vector< int> data;
- int size;
- int lbound, hbound;
- };
- array::array(int lowbound, int highbound):
- size(highbound-lowbound+1),
- lbound(lowbound),hbound(highbound),
- data(size){}
- int main()
- {
- array a(0,10);
- cout < < a.size < < '\n';
- cout < < a.data.size() < < '\n';
- }
这段程序看不出什么问题,至少一开始我看不出什么问题,但是运行的结果让我吃惊,vector< int> data的长度是一个不确定的大小。
许多人都会说,在函数的C++初始化列表中进行了初始化了么?怎么还会没有长度大小呢!其实是我们忽略了构造函数懂初始化列表的游戏规则,构造函数初始化的顺序并不是按照我们看到的在构造函数后面写的顺序,而是按照成员变量在类中的定义的顺序,所以上面
- array::array(int lowbound, int highbound):
- size(highbound-lowbound+1),
- lbound(lowbound),hbound(highbound),
- data(size){}
的运行顺序是按照下面的代码的实现顺序:
- array::array(int lowbound, int highbound):
- data(size),size(highbound-lowbound+1),
- lbound(lowbound),hbound(highbound) {}
所以当运行data(size)的时候,size还没有定义,所以在后面的测试程序中输出的data.size()的时候,就输出了一个不确定的数。
那么C++为什么要这么做呢?
我们知道,对一个对象的所有成员来说,它们的析构函数被调用的顺序总是和它们在构造函数里被创建的顺序相反。那么,如果允许上面的情况(即,成员按它们在初始化列表上出现的顺序被初始化) 发生,编译器就要为每一个对象跟踪其成员初始化的顺序,以保证它们的析构函数以正确的顺序被调用。这会带来昂贵的开销。所以,为了避免这一开销,同一种类型的所有对象在创建(构造)和摧毁(析构)过程中对成员的处理顺序都是相同的,而不管成员在C++初始化列表中的顺序如何。