程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 詳解C++ 拷貝結構函數和賦值運算符

詳解C++ 拷貝結構函數和賦值運算符

編輯:關於C++

詳解C++ 拷貝結構函數和賦值運算符。本站提示廣大學習愛好者:(詳解C++ 拷貝結構函數和賦值運算符)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解C++ 拷貝結構函數和賦值運算符正文


本文次要引見了拷貝結構函數和賦值運算符的區別,以及在什麼時分調用拷貝結構函數、什麼狀況下調用賦值運算符。最後,復雜的剖析了下深拷貝和淺拷貝的問題。

拷貝結構函數和賦值運算符

在默許狀況下(用戶沒有定義,但是也沒有顯式的刪除),編譯器會自動的隱式生成一個拷貝結構函數和賦值運算符。但用戶可以運用delete來指定不生成拷貝結構函數和賦值運算符,這樣的對象就不能經過值傳遞,也不能停止賦值運算。

class Person
{
public:
 Person(const Person& p) = delete;
 Person& operator=(const Person& p) = delete;
private:
 int age;
 string name;
};

下面的定義的類Person顯式的刪除了拷貝結構函數和賦值運算符,在需求調用拷貝結構函數或許賦值運算符的中央,會提示_無法調用該函數,它是已刪除的函數_。

還有一點需求留意的是,拷貝結構函數必需以援用的方式傳遞參數。這是由於,在值傳遞的方式傳遞給一個函數的時分,會調用拷貝結構函數生成函數的實參。假如拷貝結構函數的參數依然是以值的方式,就會有限循環的調用下去,直到函數的棧溢出。

何時調用

拷貝結構函數和賦值運算符的行為比擬類似,都是將一個對象的值復制給另一個對象;但是其後果卻有些不同,拷貝結構函數運用傳入對象的值生成一個新的對象的實例,而賦值運算符是將對象的值復制給一個曾經存在的實例。這種區別從兩者的名字也可以很隨便的分辨出來,拷貝結構函數也是一種結構函數,那麼它的功用就是創立一個新的對象實例;賦值運算符是執行某種運算,將一個對象的值復制給另一個對象(曾經存在的)。調用的是拷貝結構函數還是賦值運算符,次要是看能否有新的對象實例發生。假如發生了新的對象實例,那調用的就是拷貝結構函數;假如沒有,那就是對已有的對象賦值,調用的是賦值運算符。

調用拷貝結構函數次要有以下場景:

對象作為函數的參數,以值傳遞的方式傳給函數。  對象作為函數的前往值,以值的方式從函數前往 運用一個對象給另一個對象初始化

代碼如下:

class Person
{
public:
 Person(){}
 Person(const Person& p)
 {
 cout << "Copy Constructor" << endl;
 }
 Person& operator=(const Person& p)
 {
 cout << "Assign" << endl;
 return *this;
 }
private:
 int age;
 string name;
};
void f(Person p)
{
 return;
}
Person f1()
{
 Person p;
 return p;
}
int main()
{
 Person p;
 Person p1 = p; // 1
 Person p2;
 p2 = p; // 2
 f(p2); // 3
 p2 = f1(); // 4
 Person p3 = f1(); // 5
 getchar();
 return 0;
}

下面代碼中定義了一個類Person,顯式的定義了拷貝結構函數和賦值運算符。然後定義了兩個函數:f,以值的方式參傳入Person對象;f1,以值的方式前往Person對象。在main中模仿了5中場景,測試調用的是拷貝結構函數還是賦值運算符。執行後果如下:

剖析如下:

    這是雖然運用了"=",但是實踐上運用對象p來創立一個新的對象p1。也就是發生了新的對象,所以調用的是拷貝結構函數。 首先聲明一個對象p2,然後運用賦值運算符"=",將p的值復制給p2,顯然是調用賦值運算符,為一個曾經存在的對象賦值 。 以值傳遞的方式將對象p2傳入函數f內,調用拷貝結構函數構建一個函數f可用的實參。 這條語句拷貝結構函數和賦值運算符都調用了。函數f1以值的方式前往一個Person對象,在前往時會調用拷貝結構函數創立一個暫時對象tmp作為前往值;前往後調用賦值運算符將暫時對象tmp賦值給p2. 依照4的解釋,應該是首先調用拷貝結構函數創立暫時對象;然後再調用拷貝結構函數運用方才創立的暫時對象創立新的對象p3,也就是會調用兩次拷貝結構函數。不過,編譯器也沒有那麼傻,應該是直接調用拷貝結構函數運用前往值創立了對象p3。

深拷貝、淺拷貝

說到拷貝結構函數,就不得不提深拷貝和淺拷貝。通常,默許生成的拷貝結構函數和賦值運算符,只是復雜的停止值的復制。例如:下面的Person類,字段只要int和string兩品種型,這在拷貝或許賦值時停止值復制創立的出來的對象和源對象也是沒有任何關聯,對源對象的任何操作都不會影響到拷貝出來的對象。反之,假設Person有一個對象為int *,這時在拷貝時還只是停止值復制,那麼創立出來的Person對象的int *的值就和源對象的int *指向的是同一個地位。任何一個對象對該值的修正都會影響到另一個對象,這種狀況就是淺拷貝。

深拷貝和淺拷貝次要是針對類中的指針和靜態分配的空間來說的,由於關於指針只是復雜的值復制並不能聯系開兩個對象的關聯,任何一個對象對該指針的操作都會影響到另一個對象。這時分就需求提供自定義的深拷貝的拷貝結構函數,消弭這種影響。通常的准繩是:

含有指針類型的成員或許有靜態分配內存的成員都應該提供自定義的拷貝結構函數 在提供拷貝結構函數的同時,還應該思索完成自定義的賦值運算符

關於拷貝結構函數的完成要確保以下幾點:

關於值類型的成員停止值復制 關於指針和靜態分配的空間,在拷貝中應重新分配分配空間 關於基類,要調用基類適宜的拷貝辦法,完成基類的拷貝

總結

拷貝結構函數和賦值運算符的行為比擬類似,卻發生不同的後果;拷貝結構函數運用已有的對象創立一個新的對象,賦值運算符是將一個對象的值復制給另一個已存在的對象。區分是調用拷貝結構函數還是賦值運算符,次要能否有新的對象發生。 關於深拷貝和淺拷貝。當類有指針成員或有靜態分配空間,都應完成自定義的拷貝結構函數。提供了拷貝結構函數,最後也完成賦值運算符。

以上就是本文的全部內容,希望本文的內容對大家的學習或許任務能帶來一定的協助,假如有疑問大家可以留言交流,同時也希望多多支持!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved