成都創(chuàng)新互聯(lián)主要從事成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)廣安,十年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來(lái)電咨詢建站服務(wù):13518219792
雖然這篇文章的標(biāo)題,看起來(lái)是有點(diǎn)找抽——既然一個(gè)類是空的,那不就是說(shuō)里面啥也沒(méi)有嘛? 比如這樣:
class empty
{ };
上面定義了一個(gè)真的很空的空類,一對(duì)大括號(hào)里面除了空氣之外,真的什么都沒(méi)有!根據(jù)C++的語(yǔ)法,這樣的類是可以通過(guò)編譯的,并且可以跟別的小朋友一樣到處玩耍、奔跑和嬉鬧。look:
empty e1; // e1:“我很空虛!”
empty e2(e1); // e2:“我跟你一樣空虛!”
empty e3 = e1; // e3:“我也是!我也是!”
既然它能干這么多事情,說(shuō)明這個(gè)“空”,是內(nèi)含玄機(jī)的。
仔細(xì)觀察上面三條語(yǔ)句,會(huì)發(fā)現(xiàn)如下事實(shí):創(chuàng)建e1說(shuō)明類empty中必然有無(wú)參構(gòu)造函數(shù),創(chuàng)建e2說(shuō)明類中必然有復(fù)制構(gòu)造函數(shù),創(chuàng)建e3說(shuō)明類中必然有賦值操作符函數(shù),當(dāng)然我們還知道任何對(duì)象在釋放內(nèi)存時(shí)都會(huì)調(diào)用析構(gòu)函數(shù),因此毫無(wú)懸念類empty也必然有析構(gòu)函數(shù)。
綜上所述,你自認(rèn)為內(nèi)部只有空氣的類empty,實(shí)際上是這個(gè)樣子的:
class empty
{
public:
empty(); // 無(wú)參構(gòu)造函數(shù)
empty(const empty &rh); // 復(fù)制構(gòu)造函數(shù)
~empty(); // 析構(gòu)函數(shù)
empty & operator=(const empty &rg); // 賦值操作符函數(shù)
};
注:如果類empty繼承了虛基類,那么析構(gòu)函數(shù)也將會(huì)自動(dòng)被定義為虛函數(shù)。
原來(lái)!C++編譯器會(huì)為我們做這么多事情!
但,凡事皆有例外,以上那些不請(qǐng)自來(lái)的函數(shù)們,是不是任何時(shí)候都會(huì)出現(xiàn)呢?可不一定。請(qǐng)看精心設(shè)計(jì)的類node:
class node
{
public:
node(string &n, const int &a); // 顯式構(gòu)造函數(shù)
private:
string &name;
const int age;
};
node::node(string &n, const int &a)
: name(n), age(a)
{ }
首先,由于你提供了顯式的構(gòu)造函數(shù),因此系統(tǒng)將拒絕生成默認(rèn)的無(wú)參構(gòu)造函數(shù)。
其次,注意到類node中包含引用成員name,以及非靜態(tài)的const型成員age,他們之中的任一個(gè),都會(huì)導(dǎo)致系統(tǒng)拒絕生成默認(rèn)的賦值操作符函數(shù)。
想象一下,此時(shí)如果定義兩個(gè)node的對(duì)象x1和x2,再讓它們之間相互賦值會(huì)怎樣?
string s1("aa"), s2("bb");
node x1(s1, 100), x2(s2, 200);
x1 = x2;
由于x1.name是引用,該引用指向了字符串s1(說(shuō)白了就是x1.name就是s1的別名),那么 x1 = x2 會(huì)讓 x1.name 指向 s2 嗎? 從C++基本語(yǔ)法得知這不可能!因?yàn)橐靡坏┲付岁P(guān)聯(lián)的目標(biāo)就再也不能修改。那么, x1 = x2 會(huì)讓 x1.name指向的s1的值變?yōu)?bb"嗎? 這么一來(lái),那其他跟x1無(wú)關(guān)的但使用了字符串s1的對(duì)象豈不是要平白無(wú)故地遭受牽連?
以上分析,針對(duì)類的非靜態(tài)const型成員age而言,是一模一樣的,因?yàn)閍ge也不應(yīng)該通過(guò)類對(duì)象的賦值操作而發(fā)生改變。
因此,在上述情形下,默認(rèn)的賦值操作符函數(shù)將不復(fù)存在,如果你非要為node提供賦值操作,你必須自己顯式地定義 operator=(),否則編譯器將會(huì)在上述代碼的 x1 = x2 這一行報(bào)錯(cuò)。
事實(shí)上,還有一種情形會(huì)導(dǎo)致系統(tǒng)拒絕生成默認(rèn)賦值操作符函數(shù),那就是當(dāng)類node的基類定義了private的賦值操作符函數(shù)。這是因?yàn)?,?dāng)要賦值node對(duì)象時(shí),必須先調(diào)用基類的賦值操作符,而private的權(quán)限設(shè)定使這一想法立即破滅。
總而言之,以下情形發(fā)生時(shí)系統(tǒng)將拒絕生成默認(rèn)賦值操作函數(shù):
類中含有引用成員
類中含有非靜態(tài)const型成員
類繼承自含有private賦值操作符函數(shù)的基類
詭異的是,即便在上述條件下,系統(tǒng)依然會(huì)贊同生成默認(rèn)的拷貝構(gòu)造函數(shù),即以下代碼仍然是合法的:
string s1("aa");
node x1(s1, 100);
node x2(x1);
此時(shí),x2和x1內(nèi)的兩個(gè)引用name都指向了s1,他們中的任意一個(gè)發(fā)生了變化都將對(duì)s1產(chǎn)生影響。消除這樣的副作用的辦法是,自己定義一個(gè)復(fù)制構(gòu)造函數(shù)來(lái)達(dá)成恰當(dāng)?shù)倪壿嫛?/p> 識(shí)別下面二維碼,進(jìn)入 微店●秘籍酷 逛逛吧!