博覽網(wǎng):C++開發(fā)工程師之面向?qū)ο蟾呒壘幊蹋ㄉ希┑诙芄P記

7.Big Three:拷貝構(gòu)造,拷貝賦值,析構(gòu)

(1)什么時候需要自己寫拷貝構(gòu)造和拷貝賦值函數(shù)

當(dāng)編譯器提供的默認(rèn)拷貝構(gòu)造和拷貝賦值函數(shù)不再滿足要求的時候驻谆,比方說類里面帶指針,必須自己寫拷貝構(gòu)造和拷貝賦值函數(shù);

String(constString&?str);

String&?operator=(constString&?str);

如果不這么做昼浦,會怎么樣?如圖1所示筒主,使用默認(rèn)的拷貝構(gòu)造和拷貝賦值函數(shù)关噪,是一種淺拷貝,只會把指針拷貝過來物舒,會造成內(nèi)存泄漏色洞,同時兩個指針指向同一個地方,以后改動任何一個變量冠胯,會造成另外一個的改變。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖 1

(2)怎么寫拷貝構(gòu)造和拷貝賦值函數(shù)

拷貝構(gòu)造:①創(chuàng)造自己锦针;②拷貝

拷貝構(gòu)造函數(shù)荠察,顧名思義就是拷貝和構(gòu)造∧嗡眩拷貝構(gòu)造函數(shù),是一種特殊的構(gòu)造函數(shù)焕盟,它由編譯器調(diào)用來完成一些基于同一類的其他對象的構(gòu)建及初始化灼卢。其唯一的參數(shù)(對象的引用)是不可變的(const類型)。

如果一個類中沒有定義拷貝構(gòu)造函數(shù)沃于,那么編譯器會自動產(chǎn)生一個默認(rèn)的拷貝構(gòu)造函數(shù)繁莹,這個默認(rèn)的參數(shù)可能為X::X(const?X&)或X::X(X&),

由編譯器根據(jù)上下文決定選擇哪一個,默認(rèn)拷貝構(gòu)造函數(shù)的行為如下:默認(rèn)的拷貝構(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)建的賦值運算符對其進(jìn)行賦值

舉例:

inline

String::String(constString&?str)

{

m_data?=newchar[strlen(str.m_data)?+?1];

strcpy(m_data,?str.m_data);

}

拷貝賦值:①delete自己;②重新創(chuàng)造自己零院;③拷貝

拷貝賦值函數(shù)參數(shù)跟拷貝構(gòu)造函數(shù)相同,兩者的區(qū)別在于:構(gòu)造函數(shù)是對象創(chuàng)建并用另一個已經(jīng)存在的對象來初始化它。

賦值函數(shù)只能把一個對象賦值給另一個已經(jīng)存在的對象募疮。

注意:考慮自我拷貝的情況

舉例:

inline

String&?String::operator?=(constString&?str)

{

if(this==?&str)

return*this;

delete[]?m_data;

m_data?=newchar[strlen(str.m_data)?+?1];

strcpy(m_data,?str.m_data);

return*this;

}

(3)如果class里面有指針,多半要做動態(tài)分配

做了動態(tài)分配,則在創(chuàng)建的對象死亡之前析構(gòu)函數(shù)會被調(diào)用起來;

8.堆,棧與內(nèi)存管理

Stack(堆),是存在于某作用域(scope)的一塊內(nèi)存空間(memory space)钝域。例如當(dāng)你調(diào)用函數(shù)网梢,函數(shù)本身會形成一個Stack用來放置它所接受的參數(shù)烦感,以及返回地址手趣。

在函數(shù)本體(function body)內(nèi)聲明的任何變量(local object),其所使用的內(nèi)存塊都取自上述Stack淀散。

Heap(堆)晨抡,或者說system heap,是指由操作系統(tǒng)提供的一塊global內(nèi)存空間则剃,程序可動態(tài)分配從某種獲得若干區(qū)塊凄诞。

(1)stack objects的生命期

classComplex{...}

...

{

Complex?c1(1,2);

}

c1便是所謂的Stack object,其生命在作用于(scope)結(jié)束之際結(jié)束忍级。這種作用域內(nèi)的object,又稱為auto object伪朽,因為它會被自動清理轴咱;

(2)static local objects的生命期

classComplex?{...}

...

{

staticComplex?c2(1,2);

}

c2便是static object,其生命在作用域(scope)結(jié)束之后仍然存在,直到整個程序結(jié)束朴肺。

(3)global objects的生命期

classComplex?{...}

...

Complex?c3(1,2);

intmain()

{

...

}

c3便是所謂global object窖剑,其生命在整個程序結(jié)束之后才結(jié)束。也可以把它視為一種static object戈稿,其作用域是整個程序西土。

(4)heap objects的生命期

classComplex?{...}

...

{

Complex*?p=newComplex;

...

deletep;

}

p指的便是heap object,其生命在它被delete掉之后結(jié)束鞍盗。如果沒有delete p;會出現(xiàn)內(nèi)存泄漏(memory leak)需了,因為當(dāng)作業(yè)域結(jié)束,p所致的heap object仍然存在般甲,但指針p的生命卻結(jié)束了肋乍,作用域之外再也看不到p(也就沒有機(jī)會delete p)。

(5)new:先分配memory敷存,再調(diào)用ctor

絕大部分編譯器對調(diào)用new墓造,轉(zhuǎn)化為三步,詳見圖2

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖 2

(6)delete:先調(diào)用dtor锚烦,再釋放memory

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖 3

(7)動態(tài)分配所得的array

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖 4

(8)array new一定要搭配array delete

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖 5

10.擴(kuò)展補充:類模板觅闽,函數(shù)模板及其他

(1)static

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖 6

類complex成員函數(shù)只有一份(不可能創(chuàng)建了幾個對象就有幾個函數(shù)),但是要處理很多對象涮俄,那就得靠this pointer來處理不同的對象蛉拙。

而static的部分就和對象脫離了,它存在于內(nèi)存的一部分禽拔,只有一份刘离。

什么時候會使用static對象呢?就是和對象無關(guān)的部分睹栖。

staic成員函數(shù)和一般成員函數(shù)的特征就是static成員函數(shù)沒有this pointer硫惕,既然沒有this pointer,那static 成員函數(shù)不能和一般的函數(shù)一樣去訪問處理non-static data members野来,那只能處理static members

例如:

classAccount

{

public:

staticdoublem_rate;

staticvoidset_rate(constdouble&?x)?{m_data?=?x?};

};

doubleAccount::m_rate?=?8.0;//靜態(tài)數(shù)據(jù)必須要這樣定義恼除,因為脫離對象,

intmain()

{

Account::set_rate(5.0);

Account?a;

a.set_rate(7.0);

}

調(diào)用static函數(shù)有兩種方法:

①通過object調(diào)用曼氛;

②通過class name 調(diào)用豁辉;

(2)Singleton模式(把ctors放在private區(qū))

classA

{

public:

staticA&?getInstance();

setup()?{...}

private:

A();

A(constA&?rhs);

staticA?a;

...

};

A&?A::getInstance()

{

returna;

}

a本來就存在,和對象無關(guān)舀患,然后不想其他人創(chuàng)建徽级,那就把構(gòu)造函數(shù)放在private里,那怎么取得a呢聊浅,就用個static A& getInstance()取得a餐抢,這是與外界的接口现使。但這不是最好的寫法,因為不管你用不用旷痕,a都存在碳锈。所以更好的寫法如下:

classA

{

public:

staticA&?getInstance();

setup()?{...}

private:

A();

A(constA&?rhs);

...

};

A&?A::getInstance()

{

staticA?a;//只有當(dāng)有人掉用這個函數(shù),a才會存在

returna;

}

(3)cout

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖 7

可以看出cout就是一種ostream欺抗,實際上是重載了<<運算符的函數(shù)售碳,用于打印不同類型的數(shù)。

(4)class template绞呈,類模板

template

classcomplex

{

public:

complex?(T?r?=?0,?T?i?=?0)

:?re?(r),?im(i)

{}

complex&?operator?+=?(constcomplex&);

T?real()const{returnre;?}

T?imag()const{returnim;?}

private:

T?re,?im;

friendcomplex&?_doapl?(complex*,constcomplex&);

};

//調(diào)用如下

{

complex?c1(2.5,1.5);

complex?c2(2,6);

}

(5)function template函數(shù)模板

classstone

{

public:

stone(intw,inth,intwe)

:?_w(w),?_h(h),?_weight(we)

{}

booloperator?<?(conststone&?rhs)const

{return_weight?<?rhs._weight;?}

private:

int_w,?_h,?_weight;

};

template

inlineconstT&?min(constT&?a,constT&?b)

{

returnb?<?a???b?:?a;

}

//使用

stone?r1(2,3),?r2(3,3),?r3;

r3?=?min(r1,r2);//則會調(diào)用min函數(shù)贸人,函數(shù)里面會接著調(diào)用stone::operator<函數(shù)

(6)namespace

以防和別人寫的東西重名。

使用方法有兩種:

①using directive

usingnamespacestd;//把namspace空間的東西全打開

cin?>>?i;

cout?<<"hello"<<?endl;

②using declaration

usingstd::cout;

std::cin?>>?i;

cout?<<"hello"<<?endl;

不要在頭文件中使用using namespace std报强;灸姊,容易造成命名空間污染;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秉溉,一起剝皮案震驚了整個濱河市力惯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌召嘶,老刑警劉巖父晶,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異弄跌,居然都是意外死亡甲喝,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門铛只,熙熙樓的掌柜王于貴愁眉苦臉地迎上來埠胖,“玉大人,你說我怎么就攤上這事淳玩≈背罚” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵蜕着,是天一觀的道長谋竖。 經(jīng)常有香客問我,道長承匣,這世上最難降的妖魔是什么蓖乘? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮韧骗,結(jié)果婚禮上嘉抒,老公的妹妹穿的比我還像新娘。我一直安慰自己袍暴,他們只是感情好众眨,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布握牧。 她就那樣靜靜地躺著,像睡著了一般娩梨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上览徒,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天狈定,我揣著相機(jī)與錄音,去河邊找鬼习蓬。 笑死纽什,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的躲叼。 我是一名探鬼主播芦缰,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼枫慷!你這毒婦竟也來了让蕾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤或听,失蹤者是張志新(化名)和其女友劉穎探孝,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體誉裆,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡顿颅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了足丢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粱腻。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖斩跌,靈堂內(nèi)的尸體忽然破棺而出绍些,到底是詐尸還是另有隱情,我是刑警寧澤滔驶,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布遇革,位于F島的核電站,受9級特大地震影響揭糕,放射性物質(zhì)發(fā)生泄漏萝快。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一著角、第九天 我趴在偏房一處隱蔽的房頂上張望揪漩。 院中可真熱鬧,春花似錦吏口、人聲如沸奄容。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昂勒。三九已至蜀细,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間戈盈,已是汗流浹背奠衔。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留塘娶,地道東北人归斤。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像刁岸,于是被迫代替她去往敵國和親脏里。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容