做槍版電影網(wǎng)站賺錢(qián)免費(fèi)二級(jí)域名平臺(tái)
介紹和示例
拷貝構(gòu)造函數(shù)是一種特殊的構(gòu)造函數(shù),它在創(chuàng)建對(duì)象時(shí),是使用同一類中之前創(chuàng)建的對(duì)象來(lái)初始化新創(chuàng)建的對(duì)象??截悩?gòu)造函數(shù)通常用于:
-
通過(guò)使用另一個(gè)同類型的對(duì)象來(lái)初始化新創(chuàng)建的對(duì)象。
-
復(fù)制對(duì)象把它作為參數(shù)傳遞給函數(shù)。
-
復(fù)制對(duì)象,并從函數(shù)返回這個(gè)對(duì)象。
如果在類中沒(méi)有定義拷貝構(gòu)造函數(shù),編譯器會(huì)自行定義一個(gè)。如果類帶有指針變量,并有動(dòng)態(tài)內(nèi)存分配,則它必須有一個(gè)拷貝構(gòu)造函數(shù)??截悩?gòu)造函數(shù)的最常見(jiàn)形式如下:
//在這里,obj 是一個(gè)對(duì)象引用,該對(duì)象是用于初始化另一個(gè)對(duì)象的。
classname (const classname &obj) {// 構(gòu)造函數(shù)的主體
}
示例:
#include <iostream>using namespace std;class Line
{public:int getLength( void );Line( int len ); // 簡(jiǎn)單的構(gòu)造函數(shù)Line( const Line &obj); // 拷貝構(gòu)造函數(shù)~Line(); // 析構(gòu)函數(shù)private:int *ptr;
};// 成員函數(shù)定義,包括構(gòu)造函數(shù)
Line::Line(int len)
{cout << "調(diào)用構(gòu)造函數(shù)" << endl;// 為指針?lè)峙鋬?nèi)存ptr = new int;*ptr = len;
}Line::Line(const Line &obj)
{cout << "調(diào)用拷貝構(gòu)造函數(shù)并為指針 ptr 分配內(nèi)存" << endl;ptr = new int;*ptr = *obj.ptr; // 拷貝值
}Line::~Line(void)
{cout << "釋放內(nèi)存" << endl;delete ptr;
}
int Line::getLength( void )
{return *ptr;
}void display(Line obj)
{cout << "line 大小 : " << obj.getLength() <<endl;
}// 程序的主函數(shù)
int main( )
{Line line(10);display(line);return 0;
}
編譯執(zhí)行結(jié)果:
下面的實(shí)例對(duì)上面的實(shí)例稍作修改,通過(guò)使用已有的同類型的對(duì)象來(lái)初始化新創(chuàng)建的對(duì)象:
#include <iostream>using namespace std;class Line
{public:int getLength( void );Line( int len ); // 簡(jiǎn)單的構(gòu)造函數(shù)Line( const Line &obj); // 拷貝構(gòu)造函數(shù)~Line(); // 析構(gòu)函數(shù)private:int *ptr;
};// 成員函數(shù)定義,包括構(gòu)造函數(shù)
Line::Line(int len)
{cout << "調(diào)用構(gòu)造函數(shù)" << endl;// 為指針?lè)峙鋬?nèi)存ptr = new int;*ptr = len;
}Line::Line(const Line &obj)
{cout << "調(diào)用拷貝構(gòu)造函數(shù)并為指針 ptr 分配內(nèi)存" << endl;ptr = new int;*ptr = *obj.ptr; // 拷貝值
}Line::~Line(void)
{cout << "釋放內(nèi)存" << endl;delete ptr;
}
int Line::getLength( void )
{return *ptr;
}void display(Line obj)
{cout << "line 大小 : " << obj.getLength() <<endl;
}// 程序的主函數(shù)
int main( )
{Line line1(10);Line line2 = line1; // 這里也調(diào)用了拷貝構(gòu)造函數(shù)display(line1);display(line2);return 0;
}
編譯執(zhí)行結(jié)果:
拷貝構(gòu)造函數(shù)幾個(gè)原則:
拷貝構(gòu)造函數(shù)是一種特殊的構(gòu)造函數(shù),具有單個(gè)形參,該形參(常用const修飾)是對(duì)該類類型的引用。當(dāng)定義一個(gè)新對(duì)象并用一個(gè)同類型的對(duì)象對(duì)它進(jìn)行初始化時(shí),將顯示使用拷貝構(gòu)造函數(shù)。當(dāng)該類型的對(duì)象傳遞給函數(shù)或從函數(shù)返回該類型的對(duì)象時(shí),將隱式調(diào)用拷貝構(gòu)造函數(shù)。
C++支持兩種初始化形式:
拷貝初始化?int a = 5;?和直接初始化?int a(5);?對(duì)于其他類型沒(méi)有什么區(qū)別,對(duì)于類類型直接初始化直接調(diào)用實(shí)參匹配的構(gòu)造函數(shù),拷貝初始化總是調(diào)用拷貝構(gòu)造函數(shù),也就是說(shuō):
A x(2); //直接初始化,調(diào)用構(gòu)造函數(shù) A y = x; //拷貝初始化,調(diào)用拷貝構(gòu)造函數(shù)
必須定義拷貝構(gòu)造函數(shù)的情況:
只包含類類型成員或內(nèi)置類型(但不是指針類型)成員的類,無(wú)須顯式地定義拷貝構(gòu)造函數(shù)也可以拷貝;有的類有一個(gè)數(shù)據(jù)成員是指針,或者是有成員表示在構(gòu)造函數(shù)中分配的其他資源,這兩種情況下都必須定義拷貝構(gòu)造函數(shù)。
什么情況使用拷貝構(gòu)造函數(shù):
類的對(duì)象需要拷貝時(shí),拷貝構(gòu)造函數(shù)將會(huì)被調(diào)用。以下情況都會(huì)調(diào)用拷貝構(gòu)造函數(shù):
- (1)一個(gè)對(duì)象以值傳遞的方式傳入函數(shù)體
- (2)一個(gè)對(duì)象以值傳遞的方式從函數(shù)返回
- (3)一個(gè)對(duì)象需要通過(guò)另外一個(gè)對(duì)象進(jìn)行初始化。
關(guān)于為什么當(dāng)類成員中含有指針類型成員且需要對(duì)其分配內(nèi)存時(shí),一定要有總定義拷貝構(gòu)造函數(shù)??
默認(rèn)的拷貝構(gòu)造函數(shù)實(shí)現(xiàn)的只能是淺拷貝,即直接將原對(duì)象的數(shù)據(jù)成員值依次復(fù)制給新對(duì)象中對(duì)應(yīng)的數(shù)據(jù)成員,并沒(méi)有為新對(duì)象另外分配內(nèi)存資源。
這樣,如果對(duì)象的數(shù)據(jù)成員是指針,兩個(gè)指針對(duì)象實(shí)際上指向的是同一塊內(nèi)存空間。
在某些情況下,淺拷貝回帶來(lái)數(shù)據(jù)安全方面的隱患。
當(dāng)類的數(shù)據(jù)成員中有指針類型時(shí),我們就必須定義一個(gè)特定的拷貝構(gòu)造函數(shù),該拷貝構(gòu)造函數(shù)不僅可以實(shí)現(xiàn)原對(duì)象和新對(duì)象之間數(shù)據(jù)成員的拷貝,而且可以為新的對(duì)象分配單獨(dú)的內(nèi)存資源,這就是深拷貝構(gòu)造函數(shù)。
如何防止默認(rèn)拷貝發(fā)生
聲明一個(gè)私有的拷貝構(gòu)造函數(shù),這樣因?yàn)榭截悩?gòu)造函數(shù)是私有的,如果用戶試圖按值傳遞或函數(shù)返回該類的對(duì)象,編譯器會(huì)報(bào)告錯(cuò)誤,從而可以避免按值傳遞或返回對(duì)象。
總結(jié):
當(dāng)出現(xiàn)類的等號(hào)賦值時(shí),會(huì)調(diào)用拷貝函數(shù),在未定義顯示拷貝構(gòu)造函數(shù)的情況下,系統(tǒng)會(huì)調(diào)用默認(rèn)的拷貝函數(shù)——即淺拷貝,它能夠完成成員的一一復(fù)制。當(dāng)數(shù)據(jù)成員中沒(méi)有指針時(shí),淺拷貝是可行的。但當(dāng)數(shù)據(jù)成員中有指針時(shí),如果采用簡(jiǎn)單的淺拷貝,則兩類中的兩個(gè)指針將指向同一個(gè)地址,當(dāng)對(duì)象快結(jié)束時(shí),會(huì)調(diào)用兩次析構(gòu)函數(shù),而導(dǎo)致指針懸掛現(xiàn)象。所以,這時(shí),必須采用深拷貝。
深拷貝與淺拷貝的區(qū)別就在于深拷貝會(huì)在堆內(nèi)存中另外申請(qǐng)空間來(lái)儲(chǔ)存數(shù)據(jù),從而也就解決了指針懸掛的問(wèn)題。簡(jiǎn)而言之,當(dāng)數(shù)據(jù)成員中有指針時(shí),必須要用深拷貝。