国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
C++拷貝構(gòu)造函數(shù)
關(guān)鍵字:   C++    

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


 
1.深拷與淺拷

 深拷貝和淺拷貝的定義可以簡單理解成:如果一個類擁有資源(堆,或者是其它系統(tǒng)資源),當(dāng)這個類的對象發(fā)生復(fù)制過程的時候(復(fù)制指針?biāo)赶虻闹担@個過程就可以叫做深拷貝,反之對象存在資源但復(fù)制過程并未復(fù)制資源(只復(fù)制了指針?biāo)傅牡刂罚┑那闆r視為淺拷貝。
  淺拷貝資源后在釋放資源的時候會產(chǎn)生資源歸屬不清的情況導(dǎo)致程序運行出錯,這點尤其需要注意!    
原則上,應(yīng)該為所有包含動態(tài)分配成員的類都提供拷貝構(gòu)造函數(shù)。

淺:

 

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 拷貝構(gòu)造函數(shù)的另一種調(diào)用
當(dāng)對象直接作為參數(shù)傳給函數(shù)時,函數(shù)將建立對象的臨時拷貝,這個拷貝過程也將調(diào)用拷貝構(gòu)造函數(shù)。
例如:

#include <iostream>
using namespace std;

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

  cout 
<< "載入構(gòu)造函數(shù)" << endl;   
     n 
= i;
 }

 Date(
const Date &d)  
 

  cout 
<< "載入拷貝構(gòu)造函數(shù)" << endl;  
     n 
= d.n;
 }

 
int GetMember()
 
{
  
return n;
 }

}
;

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


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

 

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

#include <iostream>
using namespace std;

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

  cout 
<< "載入構(gòu)造函數(shù)" << endl;   
     n 
= i;
 }

 Date(
const Date &d)  
 

  cout 
<< "載入拷貝構(gòu)造函數(shù)" << endl;  
     n 
= d.n;
 }

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

}
;

Date GetClass(
void)  //函數(shù)中的局部對象被用作返回值,按理說應(yīng)該引用拷貝構(gòu)造函數(shù)
{
 Date temp(
100);
  
 
return temp;
}


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

 

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

3.3 無名對象
現(xiàn)在我們來說一下無名對象。什么是無名對象?利用無名對象初始化對象系統(tǒng)不會調(diào)用拷貝構(gòu)造函數(shù)?這是我們需要回答的兩個問題。  
首先我們來回答第一個問題。很簡單,如果在程序的main函數(shù)中有:
  Internet ("中國");  //Internet表示一個類
這樣的一句語句就會產(chǎn)生一個無名對象。
無名對象會調(diào)用構(gòu)造函數(shù),但利用無名對象初始化對象時系統(tǒng)不會調(diào)用拷貝構(gòu)造函數(shù)!
下面的代碼是常見的利用無名對象初始化對象的例子。

 

#include <iostream>
using namespace std;

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

  cout 
<< "載入構(gòu)造函數(shù)" << endl;   
     n 
= i;
 }

 Date(
const Date &d)  
 

  cout 
<< "載入拷貝構(gòu)造函數(shù)" << endl;  
     n 
= d.n;
 }

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

}
;

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

 

程序輸出:
載入構(gòu)造函數(shù):
name的地址:  23ff40;name的字符串:  中國
cname的地址:  33778;cname的字符串:  中國
載入析構(gòu)函數(shù):

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

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

(1) 沒有重載賦值函數(shù)

 

#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;
}

//結(jié)果輸出4

 

(2)重載賦值函數(shù)

 

#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. 在拷貝構(gòu)造函數(shù)中使用賦值函數(shù)
為了簡化程序,我們通常在拷貝構(gòu)造函數(shù)中使用賦值函數(shù)。
例如:

 

#include <iostream>
using namespace std;

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

  cout 
<< "載入構(gòu)造函數(shù)" << 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) //拷貝構(gòu)造函數(shù)中使用賦值函數(shù)

 cout 
<< "載入拷貝構(gòu)造函數(shù)" << endl;  
 
*this = other;
}


Date 
& Date::operator =(const Date &other)
{
 cout 
<< "載入賦值函數(shù)" << 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;
}
 

 

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

 cout << "載入拷貝構(gòu)造函數(shù)" << endl; 
 da = other.da;
 mo = other.mo;
 yr = other.yr; 
}
則程序?qū)⑤敵觯?br>載入構(gòu)造函數(shù):
3-1-6
載入拷貝構(gòu)造函數(shù)
3-1-6
載入構(gòu)造函數(shù):
0-0-0
載入賦值函數(shù)
3-1-6

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


 


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

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

聯(lián)系客服