欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
C++拷貝構造函數
關(guān)鍵字:   C++    

 默認拷貝構造函數的行為如下:
 默認的拷貝構造函數執行的順序與其他用戶(hù)定義的構造函數相同,執行先父類(lèi)后子類(lèi)的構造.
 拷貝構造函數對類(lèi)中每一個(gè)數據成員執行成員拷貝(memberwise Copy)的動(dòng)作.
 a)如果數據成員為某一個(gè)類(lèi)的實(shí)例,那么調用此類(lèi)的拷貝構造函數.
 b)如果數據成員是一個(gè)數組,對數組的每一個(gè)執行按位拷貝.
 c)如果數據成員是一個(gè)數量,如int,double,那么調用系統內建的賦值運算符對其進(jìn)行賦值.


 
1.深拷與淺拷

 深拷貝和淺拷貝的定義可以簡(jiǎn)單理解成:如果一個(gè)類(lèi)擁有資源(堆,或者是其它系統資源),當這個(gè)類(lèi)的對象發(fā)生復制過(guò)程的時(shí)候(復制指針所指向的值),這個(gè)過(guò)程就可以叫做深拷貝,反之對象存在資源但復制過(guò)程并未復制資源(只復制了指針所指的地址)的情況視為淺拷貝。
  淺拷貝資源后在釋放資源的時(shí)候會(huì )產(chǎn)生資源歸屬不清的情況導致程序運行出錯,這點(diǎn)尤其需要注意!    
原則上,應該為所有包含動(dòng)態(tài)分配成員的類(lèi)都提供拷貝構造函數。

淺:

 

using namespace std;

//shallow && deep copy
//deep copy make pointer point to a new place!
class Product
{
public:int* pointer;
Product(
int i=0)
{
pointer
=new int(i);
}

//change class variable
void change(int i)
{
    
*pointer=i;
}


//deconstructor
~Product()
{
delete pointer;
}

}
;
int main()
{
Product p1(
2);
Product p2(p1);
p1.change(
3);
cout
<<*p2.pointer<<endl;

getchar();
return 0;
}

 

深:

using namespace std;

//shallow && deep copy
//deep copy make pointer point to a new place!
class Product
{
public:int* pointer;
Product(
int i=0)
{
pointer
=new int(i);
}

//change class variable
void change(int i)
{
    
*pointer=i;
}


// copying constructor
Product(const Product &p)
{
    pointer
=new int(*p.pointer);
}

//deconstructor
~Product()
{
delete pointer;
}

}
;
int main()
{
Product p1(
2);
Product p2(p1);
p1.change(
3);
cout
<<*p2.pointer<<endl;

getchar();
return 0;
}

 

2 拷貝構造函數的另一種調用
當對象直接作為參數傳給函數時(shí),函數將建立對象的臨時(shí)拷貝,這個(gè)拷貝過(guò)程也將調用拷貝構造函數。
例如:

#include <iostream>
using namespace std;

class Date{
 
int n;
public:
 Date(
int i = 0)  
 

  cout 
<< "載入構造函數" << endl;   
     n 
= i;
 }

 Date(
const Date &d)  
 

  cout 
<< "載入拷貝構造函數" << endl;  
     n 
= d.n;
 }

 
int GetMember()
 
{
  
return n;
 }

}
;

void Display(Date obj) //針對obj的操作實(shí)際上是針對復制后的臨時(shí)拷貝進(jìn)行的
{
 cout 
<< obj.GetMember() << endl; 
}


int main()             
{
 Date a;   
 Date b(
99);   
 
 Display(a);  
//對象直接作為參數
 Display(b);  //對象直接作為參數
 
 getchar();
 
return 0;
}
 

 

程序輸出:
載入構造函數:
載入構造函數:
載入拷貝構造函數
0載入拷貝構造函數
99
還有一種情況,也是與臨時(shí)對象有關(guān)的。
當函數中的局部對象被用作返回值,返回給函數調用時(shí),也將建立此局部對象的一個(gè)臨時(shí)拷貝,此時(shí)拷貝構造函數也將被調用?!墒墙?jīng)測試發(fā)現情況有異。
代碼如下:

#include <iostream>
using namespace std;

class Date{
 
int n;
public:
 Date(
int i = 0)  
 

  cout 
<< "載入構造函數" << endl;   
     n 
= i;
 }

 Date(
const Date &d)  
 

  cout 
<< "載入拷貝構造函數" << endl;  
     n 
= d.n;
 }

 
void Show()
 
{
  cout 
<< "n = " << n << endl;
 }

}
;

Date GetClass(
void)  //函數中的局部對象被用作返回值,按理說(shuō)應該引用拷貝構造函數
{
 Date temp(
100);
  
 
return temp;
}


int main()             
{
 Date a;
 a.Show();
 
 a 
= GetClass();//這里GetClass()函數中的局部對象被用作返回值
 a.Show();
 
 Date b 
= GetClass();//這里GetClass()函數中的局部對象被用作返回值
 b.Show();
 
 getchar();
 
return 0;
}
 

 

程序輸出:
載入構造函數:
n = 0
載入構造函數:
n = 100
載入構造函數:
n = 100
按理第2個(gè)和第3個(gè)應該輸出'載入拷貝構造函數"才對,這個(gè)結果與預想的不一樣,到底是哪里出問(wèn)題了呢?
注:后來(lái)有論壇上的朋友告訴我說(shuō)這是因為編譯器的不同而導致不同的輸出。
有人得到這樣的輸出結果:
載入構造函數
n = 0
載入構造函數
載入拷貝構造函數
n = 100
載入構造函數
載入拷貝構造函數
n = 100
還有人得到這樣的輸出結果:
載入構造函數
n = 0
載入構造函數
載入拷貝構造函數
n = 100
載入構造函數
載入拷貝構造函數
載入拷貝構造函數
n = 100
(用的是vc++)

3.3 無(wú)名對象
現在我們來(lái)說(shuō)一下無(wú)名對象。什么是無(wú)名對象?利用無(wú)名對象初始化對象系統不會(huì )調用拷貝構造函數?這是我們需要回答的兩個(gè)問(wèn)題。  
首先我們來(lái)回答第一個(gè)問(wèn)題。很簡(jiǎn)單,如果在程序的main函數中有:
  Internet ("中國");  //Internet表示一個(gè)類(lèi)
這樣的一句語(yǔ)句就會(huì )產(chǎn)生一個(gè)無(wú)名對象。
無(wú)名對象會(huì )調用構造函數,但利用無(wú)名對象初始化對象時(shí)系統不會(huì )調用拷貝構造函數!
下面的代碼是常見(jiàn)的利用無(wú)名對象初始化對象的例子。

 

#include <iostream>
using namespace std;

class Date{
 
int n;
public:
 Date(
int i = 0)  
 

  cout 
<< "載入構造函數" << endl;   
     n 
= i;
 }

 Date(
const Date &d)  
 

  cout 
<< "載入拷貝構造函數" << endl;  
     n 
= d.n;
 }

 
void Show()
 
{
  cout 
<< "n = " << n << endl;
 }

}
;

int main()             
{
 Date a(
100);
 a.Show();
 
 Date b 
= a;  //"="在對象聲明語(yǔ)句中,表示初始化,調用拷貝構造函數
 b.Show();
 
 Date c;
 c.Show();  
 
 c 
= a;  //"="在賦值語(yǔ)句中,表示賦值操作,調用賦值函數
 c.Show();
 
 getchar();
 
return 0;
}
 

 

程序輸出:
載入構造函數:
name的地址:  23ff40;name的字符串:  中國
cname的地址:  33778;cname的字符串:  中國
載入析構函數:

上面代碼的運行結果有點(diǎn)“出人意料”,從思維邏輯上說(shuō),當無(wú)名對象創(chuàng )建了后,是應該調用自定義拷貝構造函數,或者是默認拷貝構造函數來(lái)完成復制過(guò)程的,但事實(shí)上系統并沒(méi)有這么做,因為無(wú)名對象使用過(guò)后在整個(gè)程序中就失去了作用。對于這種情況c++會(huì )把代碼看成是: Internet a ("中國");  省略了創(chuàng )建無(wú)名對象這一過(guò)程,所以說(shuō)不會(huì )調用拷貝構造函數。

3.賦值符的重載
 由于并非所有的對象都會(huì )使用拷貝構造函數和賦值函數,程序員可能對這兩個(gè)函數有些輕視。請先記住以下的警告,在閱讀正文時(shí)就會(huì )多心:
本章開(kāi)頭講過(guò),如果不主動(dòng)編寫(xiě)拷貝構造函數和賦值函數,編譯器將以“位拷貝”的方式自動(dòng)生成缺省的函數。倘若類(lèi)中含有指針變量,那么這兩個(gè)缺省的函數就隱含了錯誤。以類(lèi)String的兩個(gè)對象a,b為例,假設a.m_data的內容為“hello”,b.m_data的內容為“world”。
 現將a賦給b,缺省賦值函數的“位拷貝”意味著(zhù)執行b.m_data = a.m_data。這將造成三個(gè)錯誤:一是b.m_data原有的內存沒(méi)被釋放,造成內存泄露;二是b.m_data和a.m_data指向同一塊內存,a或b任何一方變動(dòng)都會(huì )影響另一方;三是在對象被析構時(shí),m_data被釋放了兩次。
拷貝構造函數和賦值函數非常容易混淆,常導致錯寫(xiě)、錯用??截悩嬙旌瘮凳窃趯ο蟊粍?chuàng )建時(shí)調用的,而賦值函數只能被已經(jīng)存在了的對象調用。以下程序中,第三個(gè)語(yǔ)句和第四個(gè)語(yǔ)句很相似,你分得清楚哪個(gè)調用了拷貝構造函數,哪個(gè)調用了賦值函數嗎?
String  a(“hello”);
String  b(“world”);
String  c = a; // 調用了拷貝構造函數,最好寫(xiě)成 c(a);
 c = b;  // 調用了賦值函數
本例中第三個(gè)語(yǔ)句的風(fēng)格較差,宜改寫(xiě)成String c(a) 以區別于第四個(gè)語(yǔ)句。
請看下面的代碼:

(1) 沒(méi)有重載賦值函數

 

#include "stdafx.h"

using namespace std;

//shallow && deep copy
//deep copy make pointer point to a new place!
class Product
{
public:int* pointer;
Product(
int i=0)
{
pointer
=new int(i);
}

//change class variable
void change(int i)
{
    
*pointer=i;
}


// copying constructor
Product(const Product &p)
{
    pointer
=new int(*p.pointer);
}

//deconstructor
~Product()
{
delete pointer;
}

}
;
int main()
{
Product p1(
1);
Product p2(
2);
Product p3(
3);
p2
=p3;
p3.change(
4);
cout
<<*p2.pointer<<endl;

getchar();
return 0;
}

//結果輸出4

 

(2)重載賦值函數

 

#include "stdafx.h"

using namespace std;

//shallow && deep copy
//deep copy make pointer point to a new place!
class Product
{
public:int* pointer;
Product(
int i=0)
{
pointer
=new int(i);
}

//change class variable
void change(int i)
{
    
*pointer=i;
}


// copying constructor
Product(const Product &p)
{
    pointer
=new int(*p.pointer);
}

//重載=
Product& operator=(const Product &p)
{
    
if(this!=&p)
pointer
=new int(*p.pointer);
    
return *this;
}

//deconstructor
~Product()
{
delete pointer;
}

}
;
int main()
{
Product p1(
1);
Product p2(
2);
Product p3(
3);
p2
=p3;
p3.change(
4);
cout
<<*p2.pointer<<endl;

getchar();
return 0;
}

//輸出3

 

 5. 在拷貝構造函數中使用賦值函數
為了簡(jiǎn)化程序,我們通常在拷貝構造函數中使用賦值函數。
例如:

 

#include <iostream>
using namespace std;

class Date{
 
int da, mo, yr;
public:
 Date(
int d = 0int m = 0int y = 0)
 

  cout 
<< "載入構造函數" << endl;   
  da 
= d;
  mo 
= m;
  yr 
= y;
 }

 Date(
const Date &other); 
 Date 
& operator =(const Date &other);
 
 
void Show() 
 
{
  cout 
<< mo << "-" << da << "-" << yr << endl; 
 }

}
;

Date::Date(
const Date &other) //拷貝構造函數中使用賦值函數

 cout 
<< "載入拷貝構造函數" << endl;  
 
*this = other;
}


Date 
& Date::operator =(const Date &other)
{
 cout 
<< "載入賦值函數" << endl;  
  
 
if(this == &other)
  
return *this;
   
 da 
= other.da;
 mo 
= other.mo;
 yr 
= other.yr; 
  
 
return *this;
}


int main()             
{
 Date a(
136);
 a.Show();
 
 Date b 
= a;
 b.Show();
 
 Date c;
 c.Show();
 
 c 
= a;
 c.Show();
 
 getchar();
 
return 0;
}
 

 

程序輸出:
載入構造函數:
3-1-6
載入拷貝構造函數
載入賦值函數
3-1-6
載入構造函數:
0-0-0
載入賦值函數
3-1-6
請注意:程序輸出了兩次“載入賦值函數”,這是因為我們在拷貝構造函數中使用了賦值函數,這樣使程序變得簡(jiǎn)潔。如果把拷貝構造函數改寫(xiě)為:
Date::Date(const Date &other)

 cout << "載入拷貝構造函數" << endl; 
 da = other.da;
 mo = other.mo;
 yr = other.yr; 
}
則程序將輸出:
載入構造函數:
3-1-6
載入拷貝構造函數
3-1-6
載入構造函數:
0-0-0
載入賦值函數
3-1-6

6. 偷懶的辦法處理拷貝構造函數和賦值函數
 如果我們實(shí)在不想編寫(xiě)拷貝構造函數和賦值函數,又不允許別人使用編譯器生成的缺省函數,怎么辦?
 偷懶的辦法是:只需將拷貝構造函數和賦值函數聲明為私有函數,不用編寫(xiě)代碼。
 例如:
 class A
 { …
   private:
  A(const A &a);    // 私有的拷貝構造函數
  A & operator =(const A &a); // 私有的賦值函數
 };
 
 如果有人試圖編寫(xiě)如下程序:
 A  b(a); // 調用了私有的拷貝構造函數
 b = a;  // 調用了私有的賦值函數
編譯器將指出錯誤,因為外界不可以操作A的私有函數。(引自〈〈高質(zhì)量c++編程指南〉〉)


 


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1666934

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
構造函數 析構函數 拷貝構造函數 this指針的使用
C++提高:拷貝構造函數
C++11/14/17
C++ 匿名對象的使用
C++類(lèi)對象的拷貝構造函數
C++拷貝構造函數詳解(轉)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久