1. 程式人生 > 其它 >C++初始化列表的一些問題

C++初始化列表的一些問題

技術標籤:學習c++程式語言

在我們建立類物件的時候,類物件的構造順序如下:

  • 分配記憶體,呼叫建構函式時,隱式/顯示的初始化各資料成員;
  • 進入建構函式後在建構函式中執行一般賦值與計算。

使用初始化列表的情況有三種:

  1. 需要初始化的資料成員是物件的情況
  2. 需要初始化const修飾的類成員以引用型別的成員資料
  3. 子類需要初始化父類的私有成員
  • 情況一的說明:資料成員是物件,並且這個物件只有含引數的建構函式,沒有無引數的建構函式;

    如果我們有一個類成員,它本身是一個類或者是一個結構,而且這個成員它只有一個帶引數的建構函式,而沒有預設建構函式,這時要對這個類成員進行初始化,就必須呼叫這個類成員的帶引數的建構函式,如果沒有初始化列表,那麼他將無法完成第一步,就會報錯。

    #include "iostream"
    using namespace std;
    class Test
    {
     public:
        Test (int, int, int){
        cout <<"Test" << endl;
     };
     private:
        int x;
        int y;
        int z;
    };
    class Mytest 
    {
     public:
        Mytest():test(1,2,3){       //初始化
        cout << "Mytest" <<
    endl; }; private: Test test; //宣告 }; int main() { Mytest test; return 0; }

輸出結果
在這裡插入圖片描述
如果沒有 mytest():test(1,2,3){} 初始化列表就會報錯

因為Test有了顯示的帶引數的建構函式,那麼他是無法依靠編譯器生成無參建構函式的,所以沒有三個int型資料,就無法建立Test的物件。Test類物件是MyTest的成員,想要初始化這個物件test,那就只能用成員初始化列表,沒有其他辦法將引數傳遞給Test類建構函式。

注意: 初始化列表在建構函式執行之前執行。

  • 情況二的說明:物件引用或者cosnt修飾的資料成員

    當類成員中含有一個const物件時,或者是一個引用時,他們也必須要通過成員初始化列表進行初始化,因為這兩種物件要在聲明後馬上初始化,而在建構函式中,做的是對他們的賦值,這樣是不被允許的。

  • 情況三的說明:子類初始化父類的私有成員,需要在(並且也只能在)引數初始化列表中顯示呼叫父類的建構函式:

程式碼如下(參考了之前學習設計模式時候的程式碼):

#include <iostream>
#include <vector>
using namespace std;

class Context {
public:
    bool isMgr;
};

class Base {
public:
    Base(Base* c = nullptr){
        cc = c;
    }
    virtual double Calc(Context& ctx) {
        printf("base/n");
        return 0.0;
    }
    virtual ~Base() {};
protected:
    Base* cc;
};

class Son1 : public Base{
public:
    Son1(Base* c) : Base(c) {}
    ~Son1() {}
    virtual double Calc(Context& ctx) {
        printf("son1\n");
        return 0.0 + cc->Calc(ctx);
    }
};

class Son2 : public Base {
public:
    Son2(Base* c) : cc(c) {}
    ~Son2() {}
    virtual double Calc(Context& ctx) {
        printf("son2\n");
        return 0.0 + cc->Calc(ctx);
    }
protected:
    Base* cc;
};

int main() {
    Context ctx1;
    ctx1.isMgr = true;
    Base* base = new Base(nullptr);
    Base* cb1 = new Son1(base);
    Base* cb2 = new Son2(cb1);
    cb2->Calc(ctx1);
    return 0;
}

注意:

  1. 初始化列表在進行初始化時的順序和類內成員宣告順序相同,和初始化順序寫法沒有關係;

  2. 預設建構函式 foo(){}foo(int i = 0){} 都是預設建構函式。兩者不能同時出現

  3. 在繼承中,只有初始化列表可以構造父類的 private 成員(需要顯式地呼叫父類地建構函式)。

    class foo {
    private:
    	int a;
    public:
    	foo(int x){
    		a = x;
    	}
    };
    
    class child : public foo{
    	child(int x):foo(x){};
    };