020_拷貝構造函數的四種調用時機

/*
    copy構造函數的調用  時機1 時機2
*/

#if 1
class Test4
{
public:
    Test4()  //無參數構造函數
    {
        m_a = 0;
        m_b = 0;
        cout << "我是構造函數,自動被調用了" << endl;
    }

    Test4(int a)
    {
        m_a = a;
        m_b = 0;
    }

    Test4(int a, int b) //有參數構造函數   //3種方法
    {
        m_a = a;
        m_b = b;
        cout << "有參數構造函數" << endl;
    }

    //賦值構造函數 (copy構造函數)  作用完成對象的初始化
    Test4(const Test4& obj)
    {
        cout << "我也是構造函數,我是通過另一個對象obj來初始化我自己 " << endl;
        m_a = obj.m_a + 100;
        m_b = obj.m_b + 100;
    }


    ~Test4()
    {
        cout << "我是析構函數,自動被調用了" << endl;
    }

public:
    void printT()
    {
        cout << "普通成員函數" << endl;
        cout << "m_a = " << m_a << ", m_b = " << m_b << endl;
    }

private:
    int m_a;
    int m_b;

};

void test()
{
    //賦值構造函數 用一個對象初始化另一個對象
    Test4 t1(10, 12);
    Test4 t0(0, 2);

    //賦值操作 和 初始化是兩個不同的概念

    //賦值 = 操作  不會調用拷貝構造函數,編譯器給我們提供的淺copy
    t0 = t1;        //用t1 給 t0賦值    

    //第一種 調用拷貝構造函數的時機
    Test4 t2 = t1;  //用t1來初始化t2,調用t2這個對象的拷貝構造函數
    t2.printT();

    //第二種 調用拷貝構造函數的時機
    Test4 t3(t1);   //用t1來初始化t2
    t3.printT();
}

#endif

這裏寫圖片描述

/*
    賦值構造函數的調用  時機3
    */
#if 1
class Location
{
public:
    //構造函數
    Location(int xx = 0, int yy = 0)
    {
        X = xx;
        Y = yy;
        cout << "Constructor Object." << endl;
    }
    //拷貝構造函數  完成對象的初始化
    Location(const Location &obj)
    {
        X = obj.X;
        Y = obj.Y;
        cout << "copy 構造函數." << endl;
    }

    ~Location()
    {
        cout << X << "," << Y << " Object destroyed." << endl;

    }
    int GetX()
    {
        return X;
    }
    int GetY()
    {
        return Y;
    }
private:
    int X, Y;
};

//第三種 調用拷貝構造函數的時機
void f(Location p)  //參數是一個元素
{
    cout << p.GetX() << endl;
}

void test()
{
    Location a(1, 2);
    Location b = a;     //第一種 調用拷貝構造函數的時機
    /*
        實參b去初始化形參p,c++編譯器會調用形參 p 這個對象的copy構造函數,
        由於p是局部變量,函數f()運行完畢,p對象的生命週期結束,會調用
        p對象的析構函數。

        先創建的對象後釋放
    */
    //b實參去初始化形參p,會調用copy構造函數 
    cout << "-------1------" << endl;
    f(b);           //第3種時機
    cout << "-------2------" << endl;
    cout << "b對象已經初始化完畢" << endl;

}
#endif

這裏寫圖片描述

/*
    賦值構造函數的調用  時機4
*/
#if 1
class Location
{
public:
    //構造函數
    Location(int xx = 0, int yy = 0)
    {
        X = xx;
        Y = yy;
        cout << "Constructor Object." << endl;
    }
    //拷貝構造函數  完成對象的初始化
    Location(const Location &obj)
    {
        X = obj.X;
        Y = obj.Y;
        cout << "copy Constructor Object." << endl;
    }

    ~Location()
    {
        cout << X << "," << Y << " Object destroyed." << endl;

    }
    int  GetX() { return X; }       int GetY() { return Y; }
private:
    int X, Y;
};

//第4種 調用拷貝構造函數的時機
Location g()
{
    Location A(11, 22);//執行對象A的構造函數
    return A;
    /*
    return A;
    這條語句  首先會創建一個匿名對象,用對象A初始化匿名對象,執行匿名對象的copy構造函數,
    然後對象A的生命週期結束了,會執行對象A的析構函數。g()返回一個匿名對象.
    */
}

//測試匿名對象的生命週期
void objplay2()
{
    g();//g()返回一個匿名對象,如果匿名對象沒人接,則會執行匿名對象的析構函數。
}


運行結果(測試匿名對象的生命週期)
這裏寫圖片描述

/*
g()函數 返回一個元素
結論 1:函數的返回值是一個元素(複雜類型的),返回一個新的匿名對象(所以會調用匿名對象
的 copy構造函數)。
結論 2:有關匿名對象的去和留
如果用匿名對象 初始化 另一個同類型的對象,匿名對象轉化爲有名對象,匿名對象不會被析構掉
如果用匿名對象 賦值給 另一個同類型的對象,匿名對象被析構
*/

void objplay3()
{
    //用匿名對象初始化m,此時c++編譯器直接把匿名對象轉成m(扶正),從匿名轉成有名對象了m
    Location m = g();
    printf("匿名對象,被扶正,不會被析構掉\n");
    cout << m.GetX() << endl;
}

運行結果(函數返回的匿名對象的去初始化另一個對象)
這裏寫圖片描述

void objplay4()
{
    Location m2(1, 2);
    m2 = g();//用匿名對象 賦值給 m2
    printf("因爲用 匿名對象 賦值 給m2, 匿名對象被析構\n");
    cout << m2.GetX() << endl;
}

運行結果(函數返回的匿名對象的去賦值另一個對象)
這裏寫圖片描述

void objplay5()
{
    //用匿名對象 賦值給 m2
    Location m1(1, 2);
    cout << "------1-----" << endl;
    m1 = Location(33, 44);  //賦值操作   Location(33, 44)會產生匿名對象,匿名對象被析構
    cout << "------2-----" << endl;
    Location m2 = Location(55, 66);//初始化操作 Location(55, 66)會產生匿名對象,匿名對象轉正,不會被析構
    cout << "------3-----" << endl;
}

運行結果:
這裏寫圖片描述

void objplay6()
{
    Location(77, 88);  //直接調用構造函數,會產生匿名對象,臨時匿名對象的生命週期  
    cout << "------1-----" << endl;
}

這裏寫圖片描述

void test()
{
    //objplay2();
    //objplay3();
    //objplay4();
    //objplay5();
    objplay6();

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