C++ 成員對象和封閉類

01 成員對象與封閉類

類裏有其餘對象則該對象叫成員對象;有成員對象的類叫 封閉類函數

class CTyre  // 輪胎類
{
public:
    // 有參數構造函數
    // 初始化成員變量m_radius和m_width
    CTyre(int r, int w):m_radius(r),m_width(w) { }
private:
    int m_radius; // 半徑
    int m_width;  // 寬度
};

class CEngine // 引擎類
{
    // 默認會有無參數構造函數
};

class CCar // 汽車類 -- 封閉類
{
public:
    // 有參數構造函數
    // 對成員變量m_price初始化,對成員對象tyre初始化
    CCar(int p, int tr, int tw):m_price(p),tyre(tr,tw){} 
private:
    int m_price;    // 價格
    CTyre tyre;     // 成員對象
    CEngine engine; // 成員對象
};

int main()
{
    CCar car(10000,20,50);
    return 0;
}

上例中,若是CCar類不定義構造函數,則會使用默認的無參構造函數,那麼下面的語句會編譯出錯:code

CCar car;

由於編譯器不明白CCar類中的tyre成員對象該如何初始化。engine成員對象的初始化則沒問題呢,由於用默認構造函數便可。對象

任何生成封閉類對象的語句,都要讓編譯器明白,對象中的成員對象,是如何初始化的。編譯器

具體的作法是:經過封閉類的構造函數的初始化列表編譯


02 封閉類構造函數和析構函數的執行順序

  • 封閉類對象生成時,先執行全部成員對象的構造函數,而後才執行封閉類的構造函數。
  • 成員對象的構造函數執行順序,與在封閉類定義成員對象的順序一致。
  • 當封閉類的對象消忙時,只須要記住一句話:先構造的對象,後析構,因爲封閉類是最後才被構造的,因此封閉類對象最早析構。
class CTyre // 輪胎類
{
public:
    CTyre(){ std::cout << "CTyre 構造函數" << std::endl; }
    ~CTyre(){ std::cout << "CTyre 析構函數" << std::endl; }
};

class CEngine // 引擎類
{
public:
    CEngine(){ std::cout << "CEngine 構造函數" << std::endl; }
    ~CEngine(){ std::cout << "CEngine 析構函數" << std::endl; }
};

class CCar // 汽車類 -- 3. 最後構造封閉類對象
{
public:
    CCar(){ std::cout << "CCar 構造函數" << std::endl; }
    ~CCar(){ std::cout << "CCar 析構函數" << std::endl; }
private:
    CTyre tyre;     // 1. 先構構造該成員對象
    CEngine engine; // 2. 接着構造該成員對象
};

int main()
{
    CCar car;
    return 0;
}

執行結果:class

CTyre 構造函數
CEngine 構造函數
CCar 構造函數
CCar 析構函數
CEngine 析構函數
CTyre 析構函數

03 封閉類的複製構造函數

class A
{
public:
    // 無參數構造函數
    A() { std::cout << "A 構造函數" << std::endl; }
    // 複製構造函數
    A(A & a) { std::cout << "A 複製構造函數" << std::endl; }
};

class B
{
    // 若沒有聲明構造函數和複製構造函數,則編譯器會默認生成構造函數和複製構造函數
    
    A a; // 成員對象
};

int main()
{
    B b1; // b1對象 和 成員對象a都會執行無參數的構造函數
    B b2(b1); // b2對象 和 成員對象a都會執行復制構造函數
    return 0;
}

輸出結果:變量

A 構造函數
A 複製構造函數
相關文章
相關標籤/搜索