日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++中的深拷贝和浅拷贝(详解)

發布時間:2025/3/15 c/c++ 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++中的深拷贝和浅拷贝(详解) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2020-07-13

拷貝構造函數是一種特殊的構造函數,在創建對象時,它是使用同一類中之前創建過的對象來初始化新創建的對象。如果沒有自定義拷貝構造函數,系統會提供一個缺省的拷貝構造函數,缺省的拷貝構造函數對于基本類型的成員變量,按字節復制,對于類類型成員變量,調用其相應類型的拷貝構造函數。

我們在編寫程序的過程中,如果不主動編寫拷貝構造函數和賦值函數,編譯器將會調用默認的函數,如果類中含有指針變量,那么如果使用的默認的函數就會有錯誤,下面首先我們先進行簡單的介紹,之后再用具體的例子來加以說明。

1.拷貝構造函數和賦值函數

拷貝構造函數,顧名思義,它是一個構造函數,所以它是在對象創建的時候被主動調用的函數,可以將 另外一個對象的變量拷貝給當前對象。賦值函數,是在對象已經存在的情況下才會進行調用。 #include <iostream> #include <set> using namespace std;class Test {public:Test() { // 默認構造函數cout << "Test()" << endl;};Test(int v) :value(v) { // 帶參數的構造函數cout << "Test(int v)" << endl;}Test(const Test& obj){ //拷貝構造函數cout << "Test(const Test& obj)" << endl;}Test& operator=(const Test& obj){cout << "Test& operator=(const Test& obj)" << endl;return *this;}~Test() { // 析構函數}private:int value; };int main() {Test a(1);Test c = a;Test d;d = a;getchar();return 0; }


(1)拷貝構造函數和賦值函數

Test c = a; d = a;

這里第一個"=“時對象c還沒有存在,所以這里調用的是拷貝構造函數,第二個”="時對象d已經存在了,所以調用的是賦值函數

(2)拷貝構造函數
拷貝構造函數是其它構造函數的重載函數,它的參數是const對象的引用,const比較容易理解,我們將一個對象拷貝給另外一個對象,那該對象的值我們是不希望被改變了的,另外一個原因是,添加 const 限制后,就可以將 const 對象和非 const 對象傳遞給形參了,因為非 const 類型可以轉換為 const 類型,如果沒有 const 限制,就不能將 const 對象傳遞給形參,因為 const 類型不能轉換為非 const 類型,這就意味著,不能使用 const 對象來初始化當前對象了;那么這里我們為什么選擇傳遞對象的引用作為函數的參數呢?一個原因是引用傳參的時候,形參是實參的一個別名,也就是說它們倆其實是相同的,但是如果我們不傳遞引用的話,在進入函數的時候,會另外分配一塊存儲空間給形參使用,形參將會初始化實參的值,在函數調用結束的時候,這塊存儲空間將會被釋放掉,如果說對象比較大的話,在這個初始化的過程中將會比較的耗時;還有一個十分重要的原因是我們在調用拷貝構造函數的時候,如果傳遞的是對象的話,由于要將實參的值賦給形參,將會調用拷貝構造函數進行賦值,那么就會形成一個死循環,如果您將上述拷貝構造函數中的"&"刪除掉,程序將會報錯。

(3)賦值函數
賦值函數用到的是運算符的重載,它的返回值是對象的引用,參數是const對象的引用。對于返回值而言,我們希望保留運算符原有的特性,考慮到a=b=c,這個賦值語句的順序應該是a=(b=c),所以賦值函數重載函數的返回值應該是類的對象,返回對象的引用是因為如果返回對象的話,將會把原先對象的值賦值給臨時的對象,這樣還會調用一次拷貝構造函數。賦值函數的參數是對象的引用,一個原因是節省時間,另外一個原因是使函數可以傳遞const的對象。

#include <iostream> using namespace std;class Test { public:Test() { // 默認構造函數cout << "Test()" << endl;};Test(int v) :value(v) { // 帶參數的構造函數cout << "Test(int v)" << endl;}Test(const Test& obj){ //拷貝構造函數cout << "Test(const Test& obj)" << endl;}Test operator=(const Test& obj){cout << "Test& operator=(const Test& obj)" << endl;return *this;}~Test() { // 析構函數}private:int value; };int main() {Test a(1);Test c = a;Test d;d = c = a;getchar();return 0; }


由于賦值函數的返回值是對象,這里在函數返回時就調用了拷貝構造函數。

2.何時調用拷貝構造函數

(1)定義一個對象時,以本類另一個對象作為初始值,發生拷貝構造。 (2)如果函數的形參是類的對象,調用函數時,將使用實參初始化形參,發生拷貝構造。 (3)如果函數的返回值是類的對象,函數執行完成返回主調函數時,將使用return語句中的對象初始化 一個臨時的無名對象,傳遞給主調函數,發生拷貝構造。

3.淺拷貝和深拷貝

淺拷貝:如果用默認的拷貝構造函數(賦值函數)去賦值有指針類型的成員變量的對象,將會使兩個對象 的指針地址也是一樣的,也就是說這兩個對象的指針成員變量指向的是相同的地址。 深拷貝:每個對象擁有自己的資源,此時需要顯示提供拷貝構造函數和賦值函數。


如果調用了默認的拷貝構造函數(賦值函數),在拷貝過程中是按字節復制的,對于指針型成員變量只復制指針本身,而不復制指針所指向的目標,這將會使同一指針指向相同的區域,同時也會導致同一塊資源被釋放多次,從而造成錯誤。
下面的例子是顯示定義的賦值函數。

#include <iostream> #include <string.h> using namespace std;class Test { public:Test():ptr(new char[1]) { // 帶參數的構造函數cout << "Test():ptr(new char[1])" << endl;}Test operator=(const Test& obj){if (this == &obj) { // s=sreturn *this;}delete[] ptr;ptr = new char[strlen(obj.ptr) + 1];strcpy(ptr, obj.ptr);cout << "Test& operator=(const Test& obj)" << endl;return *this;}Test& operator=(const char *s){delete[] ptr;ptr = new char[strlen(s) + 1];strcpy(ptr, s);cout << "Test& operator=(const Test& obj)" << endl;return *this;}~Test() { // 析構函數delete[] ptr;} private:char* ptr; };int main() {Test a;a= "test";Test b;b= a;Test d;getchar();return 0; }

總結

以上是生活随笔為你收集整理的C++中的深拷贝和浅拷贝(详解)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。