C++面向對象-4-拷貝構造函數的調用時機

繼續來學習構造函數,前面一篇學習了拷貝構造函數,至少了解了什麼是拷貝構造函數,這篇就來學習下拷貝構造的使用。什麼時候會使用到拷貝構造函數呢?大概可以分成三種場景:

  • 使用一個已經創建完畢的對象來初始化一個新對象
  • 值傳遞的方式給函數參數傳值
  • 以值方式返回局部對象

 

使用一個已經創建完畢的對象來初始化一個新對象

這個很好理解,主要是前面已經花了經歷去構造一個對象,如果我們再來一個這樣的對象,我們很容易想到克隆,當前我們沒有提供克隆方法,就可以通過拷貝構造來初始化一個新對象。

還是基於前面的代碼,這裏我們把屬性權限改成public,這裏就不寫set和get方法,方便這裏少一點代碼

#include<iostream>
using namespace std;

class Point
{

public:

    //構造函數
    Point()
    {
        cout << "調用了構造函數"<< endl;
    }

    //有參構造
    Point(int x, int y)
    {
	cout << "調用了有參構造函數" << endl;
	X = x;
	Y = y;
    }

    //拷貝構造
    Point(const Point &p)
    {
	cout << "調用了拷貝構造函數" << endl;
	//將p的屬性拷貝到當前類的初始化
	X = p.X;
	Y = p.Y;
    }

    //析構函數
    ~Point()
    {
        cout << "調用了析構函數" << endl;
    }

public:
    int X;
    int Y;
};

void test01()
{
    Point p1(10, 10);
    Point p2(p1); // 拷貝構造
    cout << "P2的X軸座標是:" << p2.X << endl;
}

int main()
{
    test01();
    system("pause");
    return 0;
}

運行結果

上面打印了p2的X座標是10,說明拷貝過來了,這種場景是我們使用拷貝構造函數的最多場景。


值傳遞的方式給函數參數傳值

先看下面代碼,再來解釋,這個有一點點繞,但是隻要記住一點就好理解。值傳遞是,先拷貝出一個值的副本,然後再傳遞給形參。對這句話理解很重要。

#include<iostream>
using namespace std;

class Point
{

public:

    //構造函數
    Point()
    {
        cout << "調用了構造函數"<< endl;
    }

    //有參構造
    Point(int x, int y)
    {
	cout << "調用了有參構造函數" << endl;
	X = x;
	Y = y;
    }

    //拷貝構造
    Point(const Point &p)
    {
	cout << "調用了拷貝構造函數" << endl;
	//將p的屬性拷貝到當前類的初始化
	X = p.X;
	Y = p.Y;
    }

    //析構函數
    ~Point()
    {
        cout << "調用了析構函數" << endl;
    }

public:
    int X;
    int Y;
};

void doSomething(Point p)
{
    // do something
}

void test01()
{
    Point p1;
    doSomething(p1);	
}


int main()
{
    test01();
    system("pause");
    return 0;
}

運行結果:

藉助上面紅圈和箭頭,我們來分析下這個代碼的執行過程。

1)執行Point p1, 這個肯定調用了默認的無參構造函數,這個理解肯定沒問題

2)開始執行doSothing(p1),p1是上一行代碼定義的,這是一個實參,doSomething(People p)這個p是形參

3)doSothing(p1)中傳入的p1(51行代碼)是實參p1(50行代碼)的一個副本,因爲這裏是值傳遞

4)這是是副本,就是一個拷貝過程,編譯器幫我們做了這個拷貝過程,所以執行了拷貝構造函數的調用

5)需要強調,假如doSomething函數中修改了X和Y的值,這個和50行代碼中p1的X和Y的值沒有任何影響,因爲兩個是完全不相同的兩個對象。


以值方式返回局部對象

也是直接來看代碼,然後進行分析

#include<iostream>
using namespace std;

class Point
{

public:

    //構造函數
    Point()
    {
        cout << "調用了構造函數"<< endl;
    }

    //有參構造
    Point(int x, int y)
    {
	cout << "調用了有參構造函數" << endl;
	X = x;
	Y = y;
    }

    //拷貝構造
    Point(const Point &p)
    {
	cout << "調用了拷貝構造函數" << endl;
	//將p的屬性拷貝到當前類的初始化
	X = p.X;
	Y = p.Y;
    }

    //析構函數
    ~Point()
    {
        cout << "調用了析構函數" << endl;
    }

public:
    int X;
    int Y;
};

Point doSomething()
{
    Point p1;
    return p1;
}

void test01()
{
    Point p = doSomething();	
}


int main()
{
    test01();
    system("pause");
    return 0;
}

運行結果

分析:

主要看doSomething()函數,第一步,Point p1,調用的時候走的是默認無參構造函數。這個函數裏面定義的Point p1是一個局部變量,函數執行完畢就會自動銷燬。關鍵點就是在這裏,return p1 這個p1和Point p1不是同一個對象,這裏是以值返回,返回拿到的這個p1是45行代碼這個p1的一個拷貝副本,所以這個時候調用了拷貝構造。

我們可以通過打印內存地址來看看p1和外面接收的p的地址是不是一樣的

 

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