类成员初始化顺序

类的初始化表的初始化顺序是根据成员变量的声明顺序来执行的,而不是按照初始化列表的顺序。
#inlude <iostream>
#inlude <string>
using namespace std;
class base
{
private:
   int m_i;
   int m_j;
public:
   base(int i) : m_j(i),m_i(m_j){}
   base() : m_j(i),m_i(m_j){}
   int get_i(){return m_i}
   int get_j(){return m_j}
}
int main()
{
   base obj(98);
   cout<<obj.get_i<<endl
   <<obj.get_j()<<endl;
   return 0;
}


分析:带一个int型参数的构造函数带有初始化列表,且初始化列表的初始化顺序是先m_j后m_i。但是实际情况却是,类的带有初始化列表的构造函数的初始化顺序是按照类成员声明顺序来初始化的。因此,该实例中,先初始化成员m_i,即将成员m_j的值赋给m_i,虽然此时m_j是个不确定的值,然后才初始化m_j。因此得到的结果是m_i是一个不确定的值,m_j为98。

一个类可以有多个构造函数,但是只有一个析构函数。在不同的构造函数中,类成员的初始化顺序可以不同,但是析构函数的析构顺序必须与初始化顺序相反,这无疑是矛盾的。因此为了简单,不论构造函数中类成员的初始化顺序如何,实现时统一按照类成员声明的先后顺序类初始化,这样,在析构时就能确保析构的顺序和初始化的顺序相反。


template<class T>
class Array {
public:
  Array(int lowBound, int highBound);
  ...
private:
  vector<T> data;              // the array data is stored
                                // in a vector object; see
                                // Item 49 for info about
                                // the vector template
  size_t size;                  // # of elements in array
  int lBound, hBound;          // lower bound, higher bound
};
template<class T>
Array<T>::Array(int lowBound, int highBound)
: size(highBound - lowBound + 1),
  lBound(lowBound), hBound(highBound),
  data(size)
{}



这是一个有上下界的数组,constructor 的初始化列表中对各个成员变量进行了初始化。但是这样会出错,因为C++总是按成员变量在类声明中出现的顺序来初始化成员变量的。在这里,这个顺序就是 data -> size -> lBound -> hBound,所以在初始化 data 时 size 还没有被初始化,也就是说,我们并不知道 data 到底会是一个多大的 vector。
为什么C++不按初始化列表的顺序来初始化成员变量呢?因为我们知道初始化的顺序应该与析构的顺序相反,也就是说,如果有两个成员变量 A 和 B ,初始化顺序为 A -> B ,那么在这个类被析构时,应该先析构 B 再析构 A。而对一个类来说 constructor 可能有多个,初始化列表也会有多个,所以如果我们要按初始化列表的顺序来进行初始化,那么我们就得记住这个顺序,以便在析构时决定析构的顺序。所以C++就选择了简单的点的方法,按成员变量出现的顺序来初始化。
既然如此,我们在写初始化列表时最好按成员变量出现的顺序来写,这样不容易出现混淆。

早上听了 Bjarne 的讲座,一到会场,果然就是我事先见到的那个老头……
老头子长得挺可爱的,脑袋上的头发掉得差不多了,就剩周围一圈。印象最深的是他在说现在的C++教材时,他说他很讨厌现在的这些教材,他们都花一两章来说那些 float int 之类的东西,他说 "If that is C++, I don't like it either."

你可能感兴趣的:(类成员初始化顺序)