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

歡迎訪問 生活随笔!

生活随笔

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

c/c++

C++类指针类型的成员变量的浅复制与深复制

發布時間:2023/12/10 c/c++ 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++类指针类型的成员变量的浅复制与深复制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

本篇文章旨在闡述C++類的構造,拷貝構造,析構機制,以及指針成員變量指針懸空問題的解決。需要讀者有較好的C++基礎,熟悉引用,const的相關知識。

引言:

? ? ?? ??? ?類作為C++語言的一種數據類型,是對C語言結構體的一種擴展。由于C++是面向過程與面向對象的混合語言,因此在使用面向對象思想解決現實問題模型時,設計好類是很重要的(跑題了)。關于類,這篇blog中有很好的介紹(鏈接http://blog.csdn.net/zqixiao_09/article/details/51474556)。我要介紹的是,關于創建一個空類,類體內都包含哪些成員函數呢?看下面例子?。

class MyClass { //創建一個空類MyClass }; void main() {MyClass c; //創建該類的對象c,此處會自動調用默認構造函數MyClass d(c); //創建一個對象d,并且用已經存在的同類對象c去初始化d,此處調用了默認拷貝構造函數MyClass e; //創建一個對象ee = c; //此處是對象賦值,調用了默認賦值運算符成員函數 }

那么我們來運行一下

?可以看到是成功的。

?以上實例說明,對于用戶定義的空類,該類會自動包含六個成員函數,分別是:

l? 默認構造函數 A(){//空函數體}

l? 默認拷貝構造函數(本次講解重點)A(const A & ){//簡單的對象成員變量賦值操作}

l? 默認析構函數 ~A(){//空函數體}

l? 賦值運算符重載成員函數(本次講解重點) A & operator =(const A &){//也是簡單的對象成員變量賦值操作}

l? 取地址操作符重載成員函數

l? Const修飾的取地址操作符重載成員函數

前四個是本次講解的內容,重點放在拷貝構造,賦值運算符重載這兩個成員函數

拷貝構造函數:

???????? 拷貝構造函數是一種特殊的構造函數,具有單個形參,該形參(常用const修飾)是對該類類型的引用。當定義一個新對象并用一個同類型的對象對它進行初始化時,將顯示使用拷貝構造函數。歸結來說。有三個場合要用到拷貝構造函數:

l? 對象作為函數的參數,以值傳遞的方式傳給函數

l? 對象作為函數的返回值,以值傳遞的方式從函數返回調用處

l? 使用一個對象去初始化一個新建的對象

????? 即有拷貝構造函數的調用一定會有新對象生成。

????? 還有一點需要注意的是,拷貝構造函數必須以引用的方式傳遞參數。這是因為,在值傳遞的方式傳遞給一個函數的時候,會調用拷貝構造函數生成函數的實參。如果拷貝構造函數的參數仍然是以值的方式,就會無限循環的調用下去,直到函數的棧溢出。

例子:

#include<iostream.h> #include<string.h> class Person{ public : Person(); //無參構造函數 Person(int age,char na[]); //重載一般構造函數 Person(const Person & p);//拷貝構造函數 ~Person(); // 析構函數 void disp(); private : int age; char *name; }; Person::Person(){ age=0; name=new char[2]; strcpy(name,"\0"); cout<<"default constructor\n";} Person::Person(int age,char na[]) { this->age=age; name=new char[strlen(na)+1]; //為指針變量動態分配空間 strcpy(name,na); //賦值 cout<<"constructor\n"; } Person::Person(const Person & p) { this->age=p.age; this->name=new char[strlen(p.name)+1]; strcpy(name,p.name); cout<<"copy constructor\n"; } Person::~Person() { delete [] name; cout<<"destroy\n"; } void Person::disp() { cout<<"age "<<age<<" name "<<name<<endl; } void f(Person p) { cout<<"enter f \n"; p.disp(); return ; } Person f1() { cout<<"enter f \n"; Person p; cout<<"next is return object of Person\n"; return p; } void main() { Person p1(21,"xiaowang");//調用一般構造函數 p1.disp(); Person p2(p1);//調用拷貝構造函數 p2.disp(); Person p3=p1;//調用拷貝構造函數 p3.disp(); cout<<"true\n"; cout<<"拷貝構造函數調用在函數形參是對象且值傳遞\n"; f(p1); //① cout<<"拷貝構造函數調用在函數返回值是對象且值傳遞\n"; f1(); //② cout<<"主函數結束,調用三次析構函數銷毀對象\n"; }

運行結果

我們來分析一下源程序①②處以及運行結果的畫線處

①? 處是函數形參是對象,且是值傳遞的情況下調用了拷貝構造函數,我們可以看到該形參對象的生存期是只在函數f里面,當函數調用結束后,就自動被析構函數清理了。但是不會引起指針懸空問題,因為如下圖所示。

???????? 其中p對象是f的形參,它由主函數調用f開始存在,由函數f調用結束而撤銷,但是析構p時不會將p1的name所指空間析構,因此最終主函數main救贖后析構p1時不會引起指針懸空問題

②? 函數返回值是對象且值傳遞返回方式時會調用靠寶貝構造函數。

分析結果會看到有兩次對象創建,在子函數f1里面先創建默認對象p,然后返回對象p到調用處,會自動調用拷貝構造,創建一個匿名的對象(記為pi),調用結束后會先析構p,在析構pi

?

賦值運算符重載成員函數

???????? 拷貝構造函數和賦值運算符的行為比較相似,都是將一個對象的值復制給另一個對象;但是其結果卻有些不同,拷貝構造函數使用傳入對象的值生成一個新的對象的實例,而賦值運算符是將對象的值復制給一個已經存在的實例。這種區別從兩者的名字也可以很輕易的分辨出來,拷貝構造函數也是一種構造函數,那么它的功能就是創建一個新的對象實例;賦值運算符是執行某種運算,將一個對象的值復制給另一個對象(已經存在的)。調用的是拷貝構造函數還是賦值運算符,主要是看是否有新的對象實例產生。如果產生了新的對象實例,那調用的就是拷貝構造函數;如果沒有,那就是對已有的對象賦值,調用的是賦值運算符。

???????? 實例:

#include<iostream.h> const int MAX=6; class Array{double * data; public:Array();Array(const Array &a);~Array();double & operator [](int i); //下標重載運算符Array & operator =(Array & a); //=重載賦值運算符Array & operator +(Array& a); //+運算符重載成員函數Array & operator -(Array & a); //-運算符重載成員函數void disp(); //輸出一個數組 }; Array::Array() {int i;data=new double[MAX];for(i=0;i<MAX;i++)data[i]=0;cout<<"construct"<<endl; } Array::Array(const Array &a) {data=a.data;cout<<"copy construct \n"; } Array::~Array() {delete [] data;cout<<"destroy"<<endl; } double& Array::operator [](int i) //返回引用類型,可以是左值 {return *(data+i); } Array& Array::operator =(Array &a) //=重載賦值運算符 {int i;for(i=0;i<MAX;i++)data[i]=a.data[i];cout<<"對象賦值,調用賦值運算符重載函數\n";return *this; } Array & Array::operator +(Array& a) {int i;static Array tmp;for(i=0;i<MAX;i++)tmp.data[i]=data[i]+a.data[i];return tmp; } Array & Array::operator -(Array & a) {for(int i=0;i<MAX;i++)data[i]-=a.data[i];return *this; } void Array::disp() {for(int i=0;i<MAX;i++)cout<<data[i]<<" ";cout<<endl; }void main() {Array a,b,c,d;cout<<"創建四個數組對象\n";cout<<"給數組a賦部分值\n";a[0]=1;a[1]=2;a[2]=3;a[3]=4;cout<<"a=";a.disp();cout<<"執行b=a\n";b=a;cout<<"b=";b.disp();cout<<"執行c=a+b\n";c=a+b;cout<<"c=";c.disp();cout<<"執行c=a+b之后a,b結果:\n";cout<<"a=";a.disp();cout<<"b=";b.disp();cout<<"執行d=a-b\n";d=a-b;cout<<"d=";d.disp();cout<<"執行d=a-b之后a,b結果:\n";cout<<"a=";a.disp();cout<<"b=";b.disp();cout<<"主函數執行完畢,銷毀四個對象和靜態成員對象\n"; }

運行結果

分析:

從結果可以看出,如果函數的形參是對象,或者返回值是對象,但是是以引用傳遞的方式,那么靠誒構造函數就不會被調用,這也是引用的作用,即對同一個對象起別名。,但要注意在賦值運算符重載成員函數中,對象的定義為靜態變量,這是為了防止子函數調用已結束就將析構該對象導致指針懸空問題。

?

深拷貝與淺拷貝

???????? 深拷貝和淺拷貝主要是針對類中的指針動態分配的空間來說的,因為對于指針只是簡單的值復制并不能分割開兩個對象的關聯,任何一個對象對該指針的操作都會影響到另一個對象。這時候就需要提供自定義的深拷貝的拷貝構造函數,消除這種影響。通常的原則是:

  • 含有指針類型的成員或者有動態分配內存的成員都應該提供自定義的拷貝構造函數
  • 在提供拷貝構造函數的同時,還應該考慮實現自定義的賦值運算符

對于拷貝構造函數的實現要確保以下幾點:

  • 對于值類型的成員進行值復制
  • 對于指針和動態分配的空間,在拷貝中應重新分配分配空間
  • 對于基類,要調用基類合適的拷貝方法,完成基類的拷貝
  • 拷貝構造函數和賦值運算符的行為比較相似,卻產生不同的結果;拷貝構造函數使用已有的對象創建一個新的對象,賦值運算符是將一個對象的值復制給另一個已存在的對象。區分是調用拷貝構造函數還是賦值運算符,主要是否有新的對象產生。
  • 關于深拷貝和淺拷貝。當類有指針成員或有動態分配空間,都應實現自定義的拷貝構造函數。提供了拷貝構造函數,最后也實現賦值運算符。

總結:

  • 拷貝構造函數和賦值運算符的行為比較相似,卻產生不同的結果;拷貝構造函數使用已有的對象創建一個新的對象,賦值運算符是將一個對象的值復制給另一個已存在的對象。區分是調用拷貝構造函數還是賦值運算符,主要是否有新的對象產生。
  • 關于深拷貝和淺拷貝。當類有指針成員或有動態分配空間,都應實現自定義的拷貝構造函數。提供了拷貝構造函數,最后也實現賦值運算符。

?

轉載于:https://www.cnblogs.com/gaochaochao/p/8370762.html

總結

以上是生活随笔為你收集整理的C++类指针类型的成员变量的浅复制与深复制的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 九九久视频 | xxxxwwww国产| 亚洲av无码乱码在线观看性色 | 日韩精品国产AV | 婷婷狠狠 | 久久鲁视频 | 手机看片在线观看 | 男人与雌性宠物交啪啪 | 99久久久无码国产精品性黑人 | 玖操| 97人人视频 | 一区二区三区偷拍 | 精品天堂 | 91亚洲网| 男生女生羞羞网站 | 边吃奶边添下面好爽 | 久久亚洲一区二区三区四区 | 免费在线观看你懂的 | 成年网站在线观看 | 亚洲美女视频在线 | 777黄色| 国产在线拍揄自揄拍无码 | 亚洲一级精品 | 韩国在线不卡 | 凸凹人妻人人澡人人添 | 最近最经典中文mv字幕 | 国产女女调教女同 | 午夜影院久久久 | 两个小y头稚嫩紧窄h文 | 免费网站观看www在线观 | 成人黄色在线网站 | 久久这里有精品视频 | 中文字幕一区二区人妻痴汉电车 | 成人导航网站 | 国产性猛交普通话对白 | 91噜噜噜| 黄色a一片 | 91麻豆精品国产91久久久久久久久 | 国内激情 | 亚洲欧美一区二区三区在线 | 国产第5页 | 四虎视频国产精品免费 | 日韩av在线播放一区 | 成人av手机在线 | 五月天精品视频 | 国产精品第一区 | 69毛片 | 精品人妻一区二区三区日产 | 国产亚洲欧美在线精品 | 国产高潮国产高潮久久久 | 成人3d动漫在线观看 | 成人国产精品一区 | 国产精品二区在线观看 | 国产三级国产精品 | 欧美69久成人做爰视频 | 羞羞的网站在线观看 | 办公室大战高跟丝袜秘书经理ol | 俺啪也| 校园春色亚洲 | 我看黄色一级片 | 国产在线午夜 | 成人久久一区二区 | 成人影视免费 | ass精品国模裸体pics | 日韩亚洲国产欧美 | 国产精品1234 | 欧美大片免费播放器 | 黄骗免费网站 | 国产免费一区二区三区最新6 | 精品无码免费视频 | 性欧美又大又长又硬 | 国产91精品久久久久久久 | 精品一区二区三区免费观看 | 97视频播放 | 欧美日韩一区二区区别是什么 | 亚洲av无码专区在线 | 韩国伦理片在线观看 | 亚洲国产精品久久久久久6q | 欧美偷拍精品 | 欧美福利一区二区三区 | 久草久草久草 | 久久看片网 | 欧美黄色一级大片 | 深夜福利视频网站 | 手机在线看永久av片免费 | 黄色国产在线观看 | 免费av大片 | 十大污网站 | 人人射 | 美女视频黄频视频大全 | 亚洲福利视频一区二区三区 | 欧美xxxx日本和非洲 | 中文字幕一区二区人妻视频 | 亚洲最新av网址 | 成人女同在线观看 | 天天综合天天做 | 嫩草综合 | 五色天婷婷| 天天摸夜夜操 |