c++-構造函數

構造函數

  • 構造和析構概念語法
  • 構造函數的分類
  • 有參構造函數3種調用方法
  • 拷貝構造函數4種調用時機
    • 場景1和2:A a(b); A a = b;
    • 場景3:形參是一個元素,實參傳遞給形參
    • 場景4:函數返回值返回一個元素,匿名對象
    • 匿名對象的去和留
    • 對象的初始化 和 對象的=操做 是兩個不一樣的概念
  • 構造和析構
    • 構造和析構概念語法
    • 構造函數的分類
    • 有參構造函數3種調用方法
    • 拷貝構造函數4種調用時機
      • 場景1和2:A a(b); A a = b;
      • 場景3:形參是一個元素,實參傳遞給形參
      • 場景4:函數返回值返回一個元素,匿名對象
      • 匿名對象的去和留
      • 對象的初始化 和 對象的=操做 是兩個不一樣的概念
    • 構造函數調用規則研究(寫了構造函數則必須調用)
    • 多個對象的構造 構造函數初始化列表
    • 構造函數和析構函數的調用順序(先組合對象的構造、本身構造;析構和構造相反)
    • 深拷貝和淺拷貝
      • 問題拋出 顯示的編寫拷貝構造函數
      • 默認的=號操做 也是淺拷貝,解決方案重載=操做符
      • 總結:C++編譯給提供的默認的拷貝構造和=操做都是淺拷貝
    • 構造和析構綜合練習
      • 匿名對象:直接調用構造函數
      • 匿名對象:構造中調用構造
  • 構造函數調用規則研究(寫了構造函數則必須調用)
  • 多個對象的構造 構造函數初始化列表
  • 構造函數和析構函數的調用順序(先組合對象的構造、本身構造;析構和構造相反)
  • 深拷貝和淺拷貝
    • 問題拋出 顯示的編寫拷貝構造函數
    • 默認的=號操做 也是淺拷貝,解決方案重載=操做符
    • 總結:C++編譯給提供的默認的拷貝構造和=操做都是淺拷貝
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>


using namespace std;

class Test
{
public:
#if 0
    void init(int x, int y)
    {
        m_x = x;
        m_y = y;
    }
#endif

    //test類的構造函數
    //在對象被建立的時候,用來初始化對象的函數
    Test()//無參數的構造函數
    {
        m_x = 0;
        m_y = 0;
    }
    Test(int x, int y)
    {
        m_x = x;
        m_y = y;
        // name = (char*)malloc(100);
        strcpy(name, "zhang3");
    }
    Test(int x)
    {
        m_x = x;
        m_y = 0;
    }

    void printT()
    {
        cout << "x = " << m_x << "  y = " << m_y << endl;
    }


    //析構函數和構造函數都沒有返回值,
    //析構函數沒有形參
    ~Test() {
        cout << "~Test()...." << endl;
        if (name != NULL) {
            // free(name);
            cout << "free succ!" << endl;
        }
    }
private:
    int m_x;
    int m_y;
    char *name;
};

void test1()
{
    Test t1(10, 20);
    t1.printT();

    //在一個對象臨死以前,要自定調用析構函數
}

int main(void)
{
#if 0
    Test t1(10, 20);
    t1.printT();
    //t1.init(10, 20);

    Test t2(100);
    t2.printT();

    Test t3;//就是調用類的無參數構造函數

    t3.printT();

#endif

    test1();
    return 0;
}

拷貝構造函數

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>


using namespace std;

class Test
{
public:
    Test()
    {
        m_x = 0;
        m_y = 0;
    }
    Test(int x, int y)
    {
        m_x = x;
        m_y = y;
    }

    void printT()
    {
        cout << "x =" << m_x << ", y = " << m_y << endl;
    }

#if 1
    //顯示的拷貝構造函數
    Test(const Test &another)
    {
        cout << "Test(const Test &)..." << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }
#endif
#if 0
    //? 會有一個默認的拷貝構造函數
    Test(const Test &another)
    {
        m_x = another.m_x;
        m_y = another.m_y;
    }
#endif

    //=賦值操做符
    void operator=(const Test &another)
    {
        m_x = another.m_x;
        m_y = another.m_y;
    }
private:
    int m_x;
    int m_y;
};

int main(void)
{
    Test t1(100, 200); 

    Test t2(t1); 

    t2.printT();



    //構造函數是對象初始化的時候調用
    Test t3; //依然是初始化t3的時候調用t3構造函數,依然是調用t3的拷貝構造函數

    t3 = t1; //調用的不是t3拷貝構造函數,而是t3的賦值操做符函數

    return 0;
}

默認的構造函數和解析構造函數

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>


using namespace std;

class Test
{
public:
    //默認的無參構造函數
#if 0
    Test()
    {

    }
#endif
    //顯示提供一個有參數的構造函數,默認的構造函數就不復存在
    Test(int x, int y)
    {
        m_x = x;
        m_y = y;
    }
    Test() {
        m_x = 0;
        m_y = 0;
    }

    void printT()
    {
        cout << "x = " << m_x << "  y = " << m_y << endl;
    }

    //默認的析構函數
#if 0
    ~Test()
    {

    }
#endif
    ~Test() {
        cout << "~Test()..." << endl;
    }


private:
    int m_x;
    int m_y;
};

int main(void)
{
    Test t1;//調用Test無參構造
    t1.printT();
    
    return 0;
}

默認的拷貝構造函數

  • 類中 會有個默認的無參構造函數:

當沒有任何顯示的構造函數(顯示的無參構,顯示有參,顯示拷貝構造) 的時候,默認無參構造函數就會出現。ios

  • 會有默認的拷貝構造函數:
    -->當沒有 顯示的拷貝構造 * 的函數,默認的拷貝構造就會出現。函數

  • 會有默認的析構函數
    --> 當沒有顯示的析構函數的時候, 默認的析構函數就會出現spa

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class A
{
public:
#if 0
    A()
    {
        
    }
#endif
#if 0
    A(const A &another)
    {
        m_a = another.m_a;
        m_b = another.m_b;
    }
#endif
    A()
    {

    }
    A(int a, int b)
    {

    }
#if 0
    ~A()
    {

    }
#endif
    ~A()
    {
        cout << "~A()" << endl;
    }
private:
    int m_a;
    int m_b;
};

//類中 會有個默認的無參構造函數:  、
//      -->當沒有任何***顯示的構造函數(顯示的無參構,顯示有參,顯示拷貝構造)*** 的時候,默認無參構造函數就會出現。

//      會有默認的拷貝構造函數:
//      -->當沒有 **顯示的拷貝構造 ***  的函數,默認的拷貝構造就會出現。

//     會有默認的析構函數
//      --> 當沒有***顯示的析構函數***的時候,  默認的析構函數就會出現。


int main(void)
{
    A a;
    
    A a1(a);
    
    return 0;
}

拷貝構造函數的應用場景

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Test
{
public:
    Test()
    {
        cout << "test()..." << endl;
        m_x = 0;
        m_y = 0;
    }
    Test(int x, int y)
    {
        cout << "Test(int x, int y)..." << endl;

        m_x = x;
        m_y = y;
    }
    Test(const Test & another)
    {
        cout << "Test(const Test &)..." << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }

    void operator=(const Test &another)
    {
        cout << "operatoer = (const Test &)" << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }

    void printT() {
        cout << "x = " << m_x << ", m_y = " << m_y << endl;
    }

    ~Test() {
        cout << "~Test()..." << endl;
    }
private:
    int m_x;
    int m_y;
};


//析構函數調用的順序, 跟構造相反, 誰先構造的,誰後析構。
//場景1
void test1()
{
    Test t1(10, 20);
    Test t2(t1);//Test t2 = t1;
}

//場景2
void test2()
{
    Test t1(10, 20);
    Test t2;

    t2 = t1;//=操做符
}


void func(Test t)//Test t = t1; //Test t 的拷貝構造函數
{
    cout << "func begin..." << endl;
    t.printT();
    cout << "func end..." << endl;
}

//場景3
void test3()
{
    cout << "test3 begin..." << endl;
    Test t1(10, 20);

    func(t1);

    cout << "test3 end..." << endl;
}


//場景4
Test func2()
{
    cout << "func2 begin..." << endl;
    Test temp(10, 20);
    temp.printT();

    cout << "func2 end..." << endl;

    return temp;
}//匿名的對象 = temp  匿名對象.拷貝構造(temp)

void test4()
{
    cout << "test4 being.. " << endl;
    func2();// 返回一個匿名對象。 當一個函數返回一個匿名對象的時候,函數外部沒有任何
            //變量去接收它, 這個匿名對象將不會再被使用,(找不到), 編譯會直接將個這個匿名對象
            //回收掉,而不是等待整改函數執行完畢再回收.
    //匿名對象就被回收。
    
    cout << "test4 end" << endl;
}

void test5()
{
    cout << "test 5begin.. " << endl;
    Test t1 = func2(); //會不會觸發t1拷貝構造來   t1.拷貝(匿名)?
                        //並不會觸發t1拷貝,而是 將匿名對象轉正 t1,
                        //把這個匿名對象 起了名字就叫t1.

    cout << "test 5 end.." << endl;
}

//場景6
void test6()
{
    cout << "test6 begin..." << endl;
    Test t1;//t1已經被初始化了。

    t1 = func2(); //t1已經被初始化了,因此func2返回的匿名對象不會再次轉正,而依然是匿名對象。
                    //因此t1會調用等號操做符,t1.operator=(匿名對象), 而後編譯器會馬上回收掉匿名對象

    t1.printT();

    cout << "test6 end.." << endl;
}


int main(void)
{
    //test1();
    //test2();
    //test3();
    //test4();
    //test5();
    test6();

    return 0;
}

深拷貝和淺拷貝

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Test
{
public:
    Test()
    {
        cout << "test()..." << endl;
        m_x = 0;
        m_y = 0;
    }
    Test(int x, int y)
    {
        cout << "Test(int x, int y)..." << endl;

        m_x = x;
        m_y = y;
    }
    Test(const Test & another)
    {
        cout << "Test(const Test &)..." << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }

    void operator=(const Test &another)
    {
        cout << "operatoer = (const Test &)" << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }

    void printT() {
        cout << "x = " << m_x << ", m_y = " << m_y << endl;
    }

    ~Test() {
        cout << "~Test()..." << endl;
    }
private:
    int m_x;
    int m_y;
};


//析構函數調用的順序, 跟構造相反, 誰先構造的,誰後析構。
//場景1
void test1()
{
    Test t1(10, 20);
    Test t2(t1);//Test t2 = t1;
}

//場景2
void test2()
{
    Test t1(10, 20);
    Test t2;

    t2 = t1;//=操做符
}


void func(Test t)//Test t = t1; //Test t 的拷貝構造函數
{
    cout << "func begin..." << endl;
    t.printT();
    cout << "func end..." << endl;
}

//場景3
void test3()
{
    cout << "test3 begin..." << endl;
    Test t1(10, 20);

    func(t1);

    cout << "test3 end..." << endl;
}


//場景4
Test func2()
{
    cout << "func2 begin..." << endl;
    Test temp(10, 20);
    temp.printT();

    cout << "func2 end..." << endl;

    return temp;
}//匿名的對象 = temp  匿名對象.拷貝構造(temp)

void test4()
{
    cout << "test4 being.. " << endl;
    func2();// 返回一個匿名對象。 當一個函數返回一個匿名對象的時候,函數外部沒有任何
            //變量去接收它, 這個匿名對象將不會再被使用,(找不到), 編譯會直接將個這個匿名對象
            //回收掉,而不是等待整改函數執行完畢再回收.
    //匿名對象就被回收。
    
    cout << "test4 end" << endl;
}

void test5()
{
    cout << "test 5begin.. " << endl;
    Test t1 = func2(); //會不會觸發t1拷貝構造來   t1.拷貝(匿名)?
                        //並不會觸發t1拷貝,而是 將匿名對象轉正 t1,
                        //把這個匿名對象 起了名字就叫t1.

    cout << "test 5 end.." << endl;
}

//場景6
void test6()
{
    cout << "test6 begin..." << endl;
    Test t1;//t1已經被初始化了。

    t1 = func2(); //t1已經被初始化了,因此func2返回的匿名對象不會再次轉正,而依然是匿名對象。
                    //因此t1會調用等號操做符,t1.operator=(匿名對象), 而後編譯器會馬上回收掉匿名對象

    t1.printT();

    cout << "test6 end.." << endl;
}


int main(void)
{
    //test1();
    //test2();
    //test3();
    //test4();
    //test5();
    test6();

    return 0;
}

構造函數的初始化列表

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Test
{
public:
    Test()
    {
        cout << "test()..." << endl;
        m_x = 0;
        m_y = 0;
    }
    Test(int x, int y)
    {
        cout << "Test(int x, int y)..." << endl;

        m_x = x;
        m_y = y;
    }
    Test(const Test & another)
    {
        cout << "Test(const Test &)..." << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }

    void operator=(const Test &another)
    {
        cout << "operatoer = (const Test &)" << endl;
        m_x = another.m_x;
        m_y = another.m_y;
    }

    void printT() {
        cout << "x = " << m_x << ", m_y = " << m_y << endl;
    }

    ~Test() {
        cout << "~Test()..." << endl;
    }
private:
    int m_x;
    int m_y;
};


//析構函數調用的順序, 跟構造相反, 誰先構造的,誰後析構。
//場景1
void test1()
{
    Test t1(10, 20);
    Test t2(t1);//Test t2 = t1;
}

//場景2
void test2()
{
    Test t1(10, 20);
    Test t2;

    t2 = t1;//=操做符
}


void func(Test t)//Test t = t1; //Test t 的拷貝構造函數
{
    cout << "func begin..." << endl;
    t.printT();
    cout << "func end..." << endl;
}

//場景3
void test3()
{
    cout << "test3 begin..." << endl;
    Test t1(10, 20);

    func(t1);

    cout << "test3 end..." << endl;
}


//場景4
Test func2()
{
    cout << "func2 begin..." << endl;
    Test temp(10, 20);
    temp.printT();

    cout << "func2 end..." << endl;

    return temp;
}//匿名的對象 = temp  匿名對象.拷貝構造(temp)

void test4()
{
    cout << "test4 being.. " << endl;
    func2();// 返回一個匿名對象。 當一個函數返回一個匿名對象的時候,函數外部沒有任何
            //變量去接收它, 這個匿名對象將不會再被使用,(找不到), 編譯會直接將個這個匿名對象
            //回收掉,而不是等待整改函數執行完畢再回收.
    //匿名對象就被回收。
    
    cout << "test4 end" << endl;
}

void test5()
{
    cout << "test 5begin.. " << endl;
    Test t1 = func2(); //會不會觸發t1拷貝構造來   t1.拷貝(匿名)?
                        //並不會觸發t1拷貝,而是 將匿名對象轉正 t1,
                        //把這個匿名對象 起了名字就叫t1.

    cout << "test 5 end.." << endl;
}

//場景6
void test6()
{
    cout << "test6 begin..." << endl;
    Test t1;//t1已經被初始化了。

    t1 = func2(); //t1已經被初始化了,因此func2返回的匿名對象不會再次轉正,而依然是匿名對象。
                    //因此t1會調用等號操做符,t1.operator=(匿名對象), 而後編譯器會馬上回收掉匿名對象

    t1.printT();

    cout << "test6 end.." << endl;
}


int main(void)
{
    //test1();
    //test2();
    //test3();
    //test4();
    //test5();
    test6();

    return 0;
}
相關文章
相關標籤/搜索