C++線下測試回顧

[題目地址](https://github.com/GeekBand/GeekBand-CPP-1501-Homework/blob/master/%E6%9E%81%E5%AE%A2%E7%8F%ADC%2B%2B%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E9%AB%98%E7%BA%A7%E7%BC%96%E7%A8%8B%E6%B5%8B%E8%AF%95%E9%A2%98(8%E6%9C%888%E6%97%A5).pdf)

首先我們要明確下規(guī)范寥假,寫函數(shù)內容的時候,最好使用this指針

this->width = width;

this->height = height;

而非:

width = width;

height = height;

為什么要這樣寫葬毫?這樣寫的好處是什么呢夭坪?

我們應該知道當局部變量名與全局變量同名時,全局變量會被覆蓋,我們自己寫構造函數(shù)的時候很可能會選擇用不同名的變量名來進行賦值操作藐守,像這樣的:

width_d = width;

height_d = height;

但最好是寫成這樣的:

this->width = width;

this->height = height;

這里的this非常明確地指出了左邊的width是當前類的成員,而不至于令別人看的時候摸不著頭腦蹂风,不清楚這里的width到底哪里的東西卢厂。

##從簡單的構造函數(shù)談起

剛拿到題的時候我是呵呵笑的,腦袋中已經有了初始模型惠啄,直到我下筆寫的時候……

說來慚愧慎恒,我寫第一個構造函數(shù)的就卡住了,磨磨蹭蹭十來分鐘過去了還是想不出怎么調用Point類里的數(shù)據(jù)成員(x, y)比較好撵渡。

原題中Rectangle類定義了一個指向Point的指針leftUp融柬。我們可以利用這個指針來對(x, y)進行構造賦值。

起初我是這樣寫的:

x = leftUp->x;

y = leftUp->y;

……編譯器啪啪啪打臉趋距,簡直不忍直視粒氧,大家?guī)兔Ψ治鱿逻@樣賦值錯在哪里?

左邊的x节腐,y到底是誰外盯?代表的是Point的成員還是另外創(chuàng)建的數(shù)據(jù)?leftUp之前只是定義了下翼雀,這個指針并未在堆中被創(chuàng)建饱苟,leftUp還沒有被實例化哪里來的成員(x,y)?

很多時候就是這樣的狼渊,感覺自己挺懂的箱熬,下筆寫出來的往編譯器來一丟立馬報一堆錯。

你說我沒有實例化囤锉,那么我來搞一個

this->leftUp = Point* ptr;

this->leftUp->x = ptr->x;

this->leftUp->y = ptr->y;

這樣乍看之下似乎無錯坦弟,但大多數(shù)負責任的編譯器仍會報錯,這是為什么呢官地?

這里涉及到設計C++類酿傍、函數(shù)要考慮到的一些東西。當我們編寫一個函數(shù)的時候通常會默認我們調用的外部的數(shù)據(jù)是安全的驱入,是可用的赤炒,同時為了保證自己的魯棒性我們要防止外部改動導致本函數(shù)的失效或者更為惡劣的程序崩潰。所以我們在對指針指向的類成員變量賦值時最好是這樣做:

this->leftUp = new Point(x, y);

直接在堆中new一個亏较,同時調用Point的默認構造函數(shù)傳進(x, y)值莺褒;

##你真的會拷貝構造嗎?

老師講完拷貝構造的時候我問了老刁雪情,你拷貝類Shape里的no了嗎遵岩?我們開始都沒注意到這個值,不過細心的網友應該記著Rectangle是繼承Shape而來的。所以他默認的數(shù)據(jù)里還是有no這個成員的尘执,你怎么能拋棄他呢舍哄?但是我們要怎么給他拷貝復制呢?

我們使用Shape(other)誊锭,直接來調用父類Shape的默認構造函數(shù)表悬。為啥可以這樣寫呢?直接調用父類不會出錯嗎丧靡?

不會的蟆沫,如果你認真看了侯捷老師的視頻,應該已經知道子温治、父類之間會為友元饭庞。

完整的代碼如下

```C++

inline

Rectangle::Rectangle(const Rectangle& other)

: Shape(other), width(other.width), height(other.height)

{

if(other.leftUp != NULL)

{

this->leftUp = new Point(*other.leftUp);

}

else

{

this->leftUp = NULL;

}

}

```

有的人可能會將函數(shù)名后緊跟的初始化操作寫成這樣的順序:

width(other.width), height(other.height), Shape(other)

這時候李老師問了一個問題:你認為拷貝構造時的順序是怎樣的?是按照你寫的初始化的順序嗎罐盔?

幾乎所有人都回答“是”但绕。

然而事實是有點坑爹的,構造函數(shù)開頭的

inline

Rectangle::Rectangle(const Rectangle& other)

: Shape(other), width(other.width), height(other.height)

并不是按照你寫的順序來的惶看,而是按照編譯器定義的優(yōu)先級來的,先是拷貝構造父類的數(shù)據(jù)六孵,然后是原類里對數(shù)據(jù)定義的順序纬黎,所以你在開頭考慮寫成什么順序并沒有什么亂用,無論你寫成什么順序劫窒,他內部都已經有約定好的順序了本今,但是為了代碼閱讀方便,讓人一看就知道拷貝構造的順序主巍,你這里只要按照他內部約定好的順序來寫冠息,先父類,后定義順序孕索,權當做個順序說明便好了逛艰。

最后我們要面對的是leftUp這個指針成員,很多人可能會直接這樣寫:

this->leftUp = new Point(*other.leftUp);

如果你拷貝的other里的leftUp是個空指針呢搞旭?我們還在堆里創(chuàng)建他干嘛散怖?

所以這里要加個if判斷。

if(other.leftUp != NULL)

{

this->leftUp = new Point(*other.leftUp);

}

else

{

this->leftUp = NULL;

}

##賦值操作符-你不造的那些事兒

只有構造函數(shù)可以這樣

Rectangle::Rectangle(const Rectangle& other)

: Shape(other), width(other.width), height(other.height)

{

···

}

在花括號之前這樣直接初始化肄渗,賦值操作符是不可以的镇眷,這是構造函數(shù)才擁有的特例。

所以我們還是老老實實用this指針吧翎嫡。不過我相信很多人會忘了在開頭寫這句判斷:

if(this == &other)

{

return *this;

}

如果他賦值操作的就是他本身欠动,我們不加判斷的直接進行操作,在處理leftUp的時候惑申,

this->leftUp = new Point(*other.leftUp);

已有的other.leftUp被再次指向了一個新的Point對象具伍,但你原來的的other.left并沒有被銷毀翅雏,原來的數(shù)據(jù)不再被記錄在案,換句話說你搞丟他了沿猜,這樣便出現(xiàn)了內存泄露枚荣。

不過不用驚訝,李老師說“大部分程序員的c++程序里必然會出現(xiàn)內存泄露的問題”啼肩,所以要想成為那少數(shù)的“大砰献保”,就從現(xiàn)在開始養(yǎng)成良好的習慣祈坠,學習畫你的數(shù)據(jù)內存模型害碾,搞清楚每一個數(shù)據(jù)的動向、聯(lián)系赦拘。確保你寫的程序萬無一失慌随。

接下來我們要思考父類Shape要怎么寫呢?

說實話躺同,我對處理繼承的父類的東西是一竅不通的阁猜,連上面那個構造函數(shù)Shape(other)都是看的別人的,看到這個直接歇菜了蹋艺。我開始寫了個這樣的

Shape(other.no);

連我自己都不知道這是什么鬼剃袍,一提筆便暴漏出很多問題來。我們幾個C++都不曉得該怎么處理捎谨,然后有人從網上找了個答案民效。寫成了醬紫:

Shape::operator=(other);

李老師后來過來看到我們這樣寫還以為我們是懂的,說這是對父類操作符重載的標準寫法涛救。

這里我們把“operator=”看做一個整體畏邢,即Shape的成員函數(shù),然后我們直接傳入?yún)?shù)other检吆,這樣便調用了shape的默認構造函數(shù)舒萎,對no進行的賦值操作,這樣做的好處是我們完全不必管Shape內部是如何實現(xiàn)的咧栗,以及是否發(fā)生改動逆甜,我們只管做我們的賦值操作就OK了。

今天李老師講的時候致板,提到了過了很多次這個思想交煞,你這個函數(shù)定義的什么功能就只做什么事情,不要直接"left->x = x"斟或,搞得你很懂外面那個類是怎么實現(xiàn)的一樣素征。很多時候我們在進行團隊合作的時候,尤其是大公司,你調用的東西一很可能不是你寫的御毅,你不知道你用的那個數(shù)據(jù)何時回發(fā)生改動根欧,所以你要保證你的通用性,魯棒性端蛆。盡量用這種寫法凤粗,否則后患無窮。

this->leftUp = new Point(x, y);

this->leftUp = new Point(*other.leftUp);

Shape::operator = (other);

賦值操作的最后我們仍要談到喜歡逗你玩的leftUp今豆。

if(other.leftUp != NULL)

{

if(leftUp != NULL ) {

*leftUp = *other.leftUp;

}

else

{

leftUp = new Point(*other.leftUp);

}

}

else

{

delete leftUp;

this->leftUp = NULL;

}

首先我們要判斷other.leftUp是否為空嫌拣,如果不為空我們就準備進行賦值操作,繼續(xù)判斷當前類成員leftUp是否為空呆躲,若為空就new一個直接在堆中初始化异逐,否則直接改變leftUp指向的內容(原來指向的會被析構函數(shù)釋放掉)。最后插掂,若要賦值的other.leftUp為空灰瞻,我們就先delete當前類中的leftUp,然后將他指向NULL辅甥。

```c++

inline

Rectangle& Rectangle::operator=(const Rectangle& other)

{

if(this == &other)

{

return *this;

}

Shape::operator = (other);

this->width = other.width;

this->height = other.height;

if(other.leftUp != NULL)

{

if(leftUp != NULL ) {

*leftUp = *other.leftUp;//直接在堆上創(chuàng)建對象進行賦值操作

}

else

{

leftUp = new Point(*other.leftUp);

}

}

else

{

delete leftUp;

this->leftUp = NULL;

}

return *this;

}

```

##析構函數(shù)

```c++

inline

Rectangle::~Rectangle()

{

delete[] leftUp;

}

```

##總結

- 測試能反映出很多問題酝润,往往你并不能將你心里所想完美無誤的實現(xiàn)出來。

- 畫內存模型圖璃弄,李老師在以前的先下課提到過袍祖,大部分時候你感覺你的程序沒問題,編譯器也沒報錯谢揪,但是仔細一分析,其實錯誤百出捐凭。有些問題只有到達了一定量級才會被你發(fā)現(xiàn)拨扶,但是畫內存模型分析圖可以避免這種尷尬的事情。

- 眼高手低要不得茁肠,看幾十遍視頻也不一定有親自實現(xiàn)一遍程序體會的深刻患民。

- 其實感覺很有問題沒寫出來,C++的東西深究起來不得了垦梆,很多事情要考慮清楚才能寫出完美無誤的代碼匹颤,而這一直是我追求的目標,我先反省下自己托猩。

- 今天聽老師單獨給我們分析印蓖,談到一些問題的時候要自己思考沒空做筆記,今天寫的這些都是記在腦子里的京腥,估計會有些遺漏赦肃,還望跟我一起接受指導的同學們批評指出。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市他宛,隨后出現(xiàn)的幾起案子船侧,更是在濱河造成了極大的恐慌,老刑警劉巖厅各,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镜撩,死亡現(xiàn)場離奇詭異,居然都是意外死亡队塘,警方通過查閱死者的電腦和手機袁梗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來人灼,“玉大人围段,你說我怎么就攤上這事⊥斗牛” “怎么了奈泪?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長灸芳。 經常有香客問我涝桅,道長,這世上最難降的妖魔是什么烙样? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任冯遂,我火速辦了婚禮,結果婚禮上谒获,老公的妹妹穿的比我還像新娘蛤肌。我一直安慰自己,他們只是感情好批狱,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布裸准。 她就那樣靜靜地躺著,像睡著了一般赔硫。 火紅的嫁衣襯著肌膚如雪炒俱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天爪膊,我揣著相機與錄音权悟,去河邊找鬼。 笑死推盛,一個胖子當著我的面吹牛峦阁,可吹牛的內容都是我干的。 我是一名探鬼主播小槐,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼拇派,長吁一口氣:“原來是場噩夢啊……” “哼荷辕!你這毒婦竟也來了?” 一聲冷哼從身側響起件豌,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤疮方,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后茧彤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骡显,經...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年曾掂,在試婚紗的時候發(fā)現(xiàn)自己被綠了惫谤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡珠洗,死狀恐怖溜歪,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情许蓖,我是刑警寧澤蝴猪,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站膊爪,受9級特大地震影響自阱,放射性物質發(fā)生泄漏。R本人自食惡果不足惜米酬,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一沛豌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赃额,春花似錦加派、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至筛严,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饶米,已是汗流浹背桨啃。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留檬输,地道東北人照瘾。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像丧慈,于是被迫代替她去往敵國和親析命。 傳聞我的和親對象是個殘疾皇子主卫,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內容