C++ 初始化列表(Initialization List)

打印 上一主题 下一主题

主题 852|帖子 852|积分 2556

  请注意以下继续体系中各class的constructors写法:
  1. 1 class CPoint
  2. 2 {
  3. 3 public:
  4. 4     CPoint(float x=0.0)
  5. 5     :_x(x){}
  6. 6     
  7. 7     float x() {return _x;}
  8. 8     void x(float xval){_x=xval;}
  9. 9 protected:
  10. 10     float _x;
  11. 11 };
  12. 12
  13. 13 class CPoint2d:public CPoint{
  14. 14
  15. 15 public:
  16. 16     CPoint2d(float x=0.0,float y=0.0)
  17. 17     :CPoint(x),_y(y){}
  18. 18
  19. 19    float y(){return _y;}
  20. 20    void y(float yval){_y=yval;}
  21. 21 protected:
  22. 22     float _y;
  23. 23 };
  24. 24
  25. 25 class CPoint3d:public CPoint2d{
  26. 26 public:
  27. 27     CPoint3d(float x=0.0,float y=0.0,float z=0.0)
  28. 28      :CPoint2d(x,y),_z(z){}
  29. 29      
  30. 30     float z(){return _z;}
  31. 31     void z(float zval){_z=zval;}
  32. 32
  33. 33 protected:
  34. 34     float _z;
  35. 35
  36. 36
  37. 37 };
复制代码
  在constructor声明之后有一个:符号,背面紧跟着一个(以上)的函数调用动作,这一行就是所谓的initialization list。它的作用是在进入constructor主体动作之前,,先唤起其中所列的函数。比方上面的:
  第5行表示:在执行CPoint::CPoint(x)之前,先执行_x(x); (注:语言内建范例如int、float、long等等也是一种class,由于变量_x的范例是float,所以_x(x)的意思是启动“float class”的constrnctor,也就把_x的初值设为x;
  第17行表示:执行CPoint2d::CPoint2d(x,y)之前,先执行CPoint(x)和_y(y).
  第28行表示:执行CPoint3d::CPoint3d(x,y,z)之前,先执行CPoint2d(x,y)和_z(z).
  因此当我产生一个CPoint3d object如下:
  1. CPoint3d aPoint3d(1.1, 2.2, 3.3);
复制代码
  会有以下六个动作依序被调用:
  1. _x(1.1); // 相当于 _x = 1.1;
  2. CPoint::CPoint(1.1); // 本例沒做什么事
  3. _y(2.2); // 相当于 _y = 2.2;
  4. CPoint2d::CPoint2d(1.1, 2.2); // 本例沒做什么事
  5. _z(3.3); // 相当于_z = 3.3;
  6. CPoint3d::CPoint3d(1.1, 2.2, 3.3); // 本例沒做什么事
复制代码
  你大概会问,既然继续体系中的建构方式是由内而外,由上而下,那么这里产生个CPoint3d object,必然会调用CPoint2d和CPoint的constrnctor,而所有初始化动作都可以在其中完成,initialization list的出现会不会是显得多此一举?做个测试就知道了,把上一段27行的代码改为这样试试:
  1. CPoint3d( float x = 0.0, float y = 0.0, float z = 0.0 ) { _z = z; }
复制代码
  其中没有指定initialzation list。效果竟然无法通过编译:
  1. error C2668: 'CPoint2d::CPoint2d' : ambiguous call to overloaded
  2. function
复制代码
  也就是说,当编译器根据继续体系往上一层调用base class constructor时,发现CPoint2d有两个constructors,而它不知道应该调用哪一个。这就是initialization list最显着的存在的价值。如果本例的CPoint2d只有一个constructor,像这样:
  1. 1 class CPoint2d : public CPoint {
  2. 2 public:
  3. 3   CPoint2d( ) { _y = 0.0; } // default constructor
  4. 4 protected:
  5. 5   float _y;
  6. 6 };
复制代码
  或者这样
  1. 1 class CPoint2d : public CPoint {
  2. 2 public:
  3. 3     CPoint2d( float x = 0.0, float y = 0.0 )
  4. 4     : CPoint( x ), _y( y ) { }
  5. 5 protected:
  6. 6     float _y;
  7. 7 };
复制代码
  而 CPoint3d constructor 中沒有列出 initialization list,像这样:
  1. 1 class CPoint3d : public CPoint2d {
  2. 2 public:
  3. 3     CPoint3d( float x = 0.0, float y = 0.0, float z = 0.0 ) { _z = z; }
  4. 4 protected:
  5. 5     float _z;
  6. 6 };
复制代码
  那么并不会出现前面的编译错误。
  以上的讨论是针对base class的建构,同理对于member class 也是一样。如果member calss有一个以上的constructors,那么内含embedded object的那个class就必须在其constructor中指定initialization list,否则一样会出现编译错误。
  initialization list到底会在编译器底层发生什么影响呢?编译器会以“适当的次序”将initialization list中指定的member调用动作安插到constructor之内,并置于任何user code之前,下面这张图可以表现出编译器的插码效果:

 
   有一些微妙的地方必须注意,编译器安插在constructor中的members声明动作是以members在class中的声明次序为根据,而不是以initializtion list中的排序为根据。如果两者在表面上错乱,很容易引起程序设计时的一些困扰或失误。比方:
  1. class X {
  2. public:
  3.     X(int val) : m_data2(val), m_data1(m_data2) { }
  4. protected:
  5.     int m_data1;
  6.     int m_data2;
  7. };
复制代码
  我们很容易误以为在X constructor中是以val 设定m_data2,再将m_data2设定给m_data1.但根据两个data members的声明顺序,实际发生的动作却是:
  1. 1 X::X(int val)
  2. 2 {
  3. 3     m_data1(m_data2); // 此时 m_data2 还没有初值,糟糕
  4. 4     m_data2(val);
  5. 5 }
复制代码
  于是,当我们产生一个X object:
  1. X x(3);
复制代码
  其实data members的内容大概成为这样:
  1. x.m_data1 = -2124198216 // 这不是我们希望的
  2. x.m_data2 = 3
复制代码
一个比较好的做法是,把class X重新设计如下:
  1. 1 class X {
  2. 2 public:
  3. 3     X(int val) : m_data2(val) { m_data1 = m_data2; }
  4. 4 protected:
  5. 5     int m_data1;
  6. 6     int m_data2;
  7. 7 };
复制代码
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

悠扬随风

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表