構造函數拓展

1、默認構造函數
如果類中沒有定義任何構造函數,編譯器會自動生成一個無參構造函數,沒有做任何事情, 如果寫了構造函數,編譯器將不再提供默認的無參構造函數,如果還還想進行無參構造,需要顯示定義無參構造函數
如果沒有定義拷貝構造函數,編譯器會自動生成一個拷貝構造函數,會做普通類型數據的複製。
還會生成一個默認的 析構函數。

class Test7_2
{
    Test7_2() {}
    Test7_2(const Test7_2 &obj) {}

    ~Test7_2(){};
};

如果沒有定義拷貝構造函數,會默認生成一個拷貝函數,但如果我們不想被拷貝呢?(隨意的拷貝構造函數可能會出現訪問非法內存的問題,下文會講到)怎麼達到這一目的呢?
很簡單,我們只需要將拷貝構造寫成私有的函數,只需聲明,不需要實現

private:
    Test8_3(const Test8_3 &ibj);

這樣就可以達到這一目的了。

2、構造函數的一些規則:
1)當類中沒有定義任何一個構造函數時,c++編譯器會提供默認無參構造函數和默認拷貝構造函數
2)當類中定義了拷貝構造函數時,c++編譯器不會提供無參數構造函數
3)當類中定義了任意的非拷貝構造函數(即:當類中提供了有參構造函數或無參構造函數),c++編譯器不會提供默認無參構造函數
4 )默認拷貝構造函數成員變量簡單賦值
只要你寫了構造函數,那麼你必須用。
總結:
1)構造函數是C++中用於初始化對象狀態的特殊函數
2)構造函數在對象創建時自動被調用
3)構造函數和普通成員函數都遵循重載規則
4)拷貝構造函數是對象正確初始化的重要保證
5)必要的時候,必須手工編寫拷貝構造函數

3、對象初始化列表(多個對象構造和析構)
對象初始化列表出現原因
1)必須這樣做:
如果我們有一個類成員,它本身是一個類或者是一個結構,而且這個成員它只有一個帶參數的構造函數,沒有默認構造函數。這時要對這個類成員進行初始化,就必須調用這個類成員的帶參數的構造函數,如果沒有初始化列表,那麼他將無法完成第一步,就會報錯。

2)類成員中若有const修飾,必須在對象初始化的時候,給const int m 賦值,當類成員中含有一個const對象時,或者是一個引用時,他們也必須要通過成員初始化列表進行初始化,因爲這兩種對象要在聲明後馬上初始化,而在構造函數中,做的是對他們的賦值,這樣是不被允許的。

class Test9_1
{
public:
    Test9_1 (int a)
    {
        m_a = a;
        printf ("9_1 1111111111111111111構造函數....a: %d\n", a);
    }

    // 析構的順序和構造的順序相反,先構造的後析構
    ~Test9_1()
    {
        printf ("9_1 1111111111111111111析構函數....a: %d\n", m_a);
    }
private:
    int m_a;
};

int main()
{

    // Test9_1 a;

    return 0;
}

類中有了構造函數以後,就沒有默認的無參構造
所以這樣的函數中我們無法同過Test9_1 a來創造一個對象
這時對象初始化列表就可以解決一個類中有另一個沒有無參構造的類的對象的初始化


class Test9_2
{
// 對象初始化列表,在構造函數後面加:,後面加上要初始化的對象
// 對象初始化列表要比當前類的構造函數先執行
// 對象的初始化先後順序和 在對象初始化列表 的順序無關,和在類中的聲明先後順序有關 
public: 
    Test9_2():m_a(10), m_b(20), m_c(30), m_ca(100)
    {

        printf ("9_2 222222222222構造函數....\n");
    }

    ~Test9_2()
    {
        printf ("9_2 222222222222構造函數....a: %d\n", m_ca);
    }
private:
    Test9_1 m_b;
    Test9_1 m_c;
    Test9_1 m_a;

    const int m_ca;
};

加了這樣一個初始化列表後我們就可以通過Test9_2 t對沒有默認構造函數的類成員初始化。

4、構造函數和析構函數的調用順序
1)當類中有成員變量是其它類的對象時,首先調用成員變量的構造函數,調用順序與聲明順序相同;之後調用自身類的構造函數
2)析構函數的調用順序與對應的構造函數調用順序相反

5、構造函數中調用構造函數

class Test10_1
{
//構造函數中調用構造函數 不會達到預期的效果的
public:
    Test10_1(int a, int b)
    {
        m_a = a;
        m_b = b;

        Test10_1(a, b, 30);  // 匿名對象、臨時對象
    }

    Test10_1 (int a, int b, int c)
    {
        m_a = a;
        m_b = b;
        m_c = c;
    }

    ~Test10_1()
    {
        printf ("析構*******a = %d, b = %d, c = %d\n", m_a, m_b, m_c);
    }
    void print ()
    {
        printf ("a = %d, b = %d, c = %d\n", m_a, m_b, m_c);
    }
private:
    int m_a;
    int m_b;
    int m_c;
};

int main10_1()
{
    Test10_1 a(10,20);
    a.print();

    printf ("--------------------------------\n");

    return 0;
}

在這個函數執行後我們發現,並不能打印出c的值,所以在構造函數中構造並不能達到預期的目的。最終的結果還是由提供的參數決定。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章