1. 程式人生 > >C++ 建構函式初始化呼叫順序及類函式內部巢狀函式情況

C++ 建構函式初始化呼叫順序及類函式內部巢狀函式情況

C++建構函式初始化順序

C++建構函式按下列順序被呼叫:(1、2、3、4是按照優先順序順序來的!)
(1)任何虛擬基類的建構函式按照它們被繼承的順序構造;
(2)任何非虛擬基類的建構函式按照它們被繼承的順序構造;
(3)任何成員物件的建構函式按照它們宣告的順序呼叫;(如果成員物件有前面出現過的父類,那麼還會呼叫此物件父類的建構函式一遍,因為第一遍(1)(2)是為了建立子類,第二遍呼叫是為了構造裡面的成員物件。)
(4)類自己的建構函式。
  例子:

class B1
  {
  public:
    B1(int i){cout<<"constructing B1"<<i<<endl;}
  };
  class B2
  {
  public:
    B2(int j){cout<<"constructing B2"<<j<<endl;}
  };
  class B3
  {
    public:
      B3(){cout<<"constructing B3*"<<endl;}
  };
  class C: public B2, public B1, public B3
  {
    public:
      C(int a, int b, int c, intd):B1(a),memberB2(d),memberB1(c),B2(b){}
    private:
      B1 memberB1;
      B2 memberB2;
      B3 memberB3;
  };
  void main( )
  { 
        C obj(1,2,3,4); 
  }
  //執行後的結果如下:
  constructing B2 2
  constructing B1 1
  constructing B3 *
  constructing B1 3
  constructing B2 4
  constructing B3 *

眾所周知建構函式的執行次序如下:
  呼叫基類建構函式,呼叫順序按照他們的繼承時宣告的順序。
  呼叫內嵌成員物件的建構函式,呼叫順序按照他們在類中宣告的順序。
  派生類的建構函式體中的內容。
  解構函式的呼叫順序相反。
 那麼再來看以上的例子就很容易理解了。B2、B1、B3是C的基類,按照上述的順序,我們先要構造基類,然後才是子物件,最後是其本身的建構函式所以先要執行這三個類的建構函式。在構造時按照他們在類中的順序,首先呼叫B2的建構函式
  B2(int j){cout<<"constructing B2"<<j<<endl;}
  由於在預設引數列表
  C(int a, int b, int c, intd):B1(a),memberB2(d),memberB1(c),B2(b){}
  中,將b的值傳給了B2的建構函式,b為2,故打印出:
  constructing B2 2
  接下來要構造的是B1了。顯然在C的預設引數構造列表中將a的值傳給了B1,
  所以打印出:
  constructing B1 1
  B3在構造時沒有傳遞引數,呼叫B3(){cout<<"constructing B3*"<<endl;}
  打印出:
 cout<<"constructing B3 *
  這時基類的建構函式已經執行完畢,接著該處理內嵌成員物件的構造函數了。
  我們看到C類有三個物件:B1 memberB1;B2 memberB2;B3memberB3;,按照建構函式的呼叫順序,我們需要按照他們在類中宣告的順序來分別構造memberB1、memberB2、memberB3。在預設的引數列表中,用c來構造了memberB1,用d來構造memberB2,
  故打印出:
  constructing B1 3
  constructing B2 4
  constructing B3 *
  最後呼叫本身的建構函式,由於函式體為空,故什麼也沒有打印出來。
 總結 : 我們必須明確的是當一個類繼承與基類,並且自身還包含有其他類的成員物件的時候,建構函式的呼叫順序為:呼叫基類的建構函式->呼叫成員物件的建構函式->呼叫自身的建構函式。建構函式的呼叫次序完全不受建構函式初始化列表的表示式中的次序影響,與基類的宣告次數和成員物件在函式中的宣告次序有關。