題目位址
首先我們要明確下格式規範,寫函式內容的時候,最好使用this指標
this->width = width;
this->height = height;
而非:
width = width;
height = height;
為什麼要這樣寫?這樣寫的好處是什麼呢?
我們應該知道當區域性變數名與全域性變數同名時,全域性變數會被覆蓋,我們自己寫建構函式的時候很可能會選擇用不同名的變數名來進行賦值操作,像這樣的:
width_d = width;
height_d = height;
但最好是寫成這樣的:
this->width = width;
this->height = height;
這裡的this非常明確地指出了左邊的width是當前類的成員,而不至於令別人看的時候摸不著頭腦,不清楚這裡的width到底**的東西。
剛拿到題的時候我是呵呵笑的,腦袋中已經有了初始模型,直到我下筆寫的時候……
說來慚愧,我寫第乙個建構函式的就卡住了,磨磨蹭蹭十來分鐘過去了還是想不出怎麼呼叫point類裡的資料成員(x, y)比較好。
原題中rectangle類定義了乙個指向point的指標leftup。我們可以利用這個指標來對(x, y)進行構造賦值。
起初我是這樣寫的:
x = leftup->x;
y = leftup->y;
……編譯器啪啪啪打臉,簡直不忍直視,大家幫忙分析下這樣賦值錯在**?
左邊的x,y到底是誰?代表的是point的成員還是另外建立的資料?leftup之前只是定義了下,這個指標並未在堆中被建立,leftup還沒有被例項化**來的成員(x,y)?
很多時候就是這樣的,感覺自己挺懂的,下筆寫出來的往編譯器來一丟立馬報一堆錯。
你說我沒有例項化,那麼我來搞乙個
this->leftup = point* ptr;
this->leftup->x = ptr->x;
this->leftup->y = ptr->y;
這樣乍看之下似乎無錯,但大多數負責任的編譯器仍會報錯,這是為什麼呢?
這裡涉及到設計c++類、函式要考慮到的一些東西。當我們編寫乙個函式的時候通常會預設我們呼叫的外部的資料是安全的,是可用的,同時為了保證自己的魯棒性我們要防止外部改動導致本函式的失效或者更為惡劣的程式崩潰。所以我們在對指標指向的類成員變數賦值時最好是這樣做:
this->leftup = new point(x, y);
直接在堆中new乙個,同時呼叫point的預設建構函式傳進(x, y)值;
老師講完拷貝構造的時候我問了老刁,你拷貝類shape裡的no了嗎?我們開始都沒注意到這個值,不過細心的網友應該記著rectangle是繼承shape而來的。所以他預設的資料裡還是有no這個成員的,你怎麼能拋棄他呢?但是我們要怎麼給他拷貝複製呢?
我們使用shape(other),直接來呼叫父類shape的預設建構函式。為啥可以這樣寫呢?直接呼叫父類不會出錯嗎?
完整的**如下
inline
rectangle::rectangle(const rectangle& other)
: shape(other), width(other.width), height(other.height)
else
}
有的人可能會將函式名後緊跟的初始化操作寫成這樣的順序:
width(other.width), height(other.height), shape(other)
這時候***問了乙個問題:你認為拷貝構造時的順序是怎樣的?是按照你寫的初始化的順序嗎?
幾乎所有人都回答「是」。
然而事實是有點坑爹的,建構函式開頭的
inline
rectangle::rectangle(const rectangle& other)
: shape(other), width(other.width), height(other.height)
並不是按照你寫的順序來的,而是按照編譯器定義的優先順序來的,先是拷貝構造父類的資料,然後是原類裡對資料定義的順序,所以你在開頭考慮寫成什麼順序並沒有什麼亂用,無論你寫成什麼順序,他內部都已經有約定好的順序了,但是為了**閱讀方便,讓人一看就知道拷貝構造的順序,你這裡只要按照他內部約定好的順序來寫,先父類,後定義順序,權當做個順序說明便好了。
最後我們要面對的是leftup這個指標成員,很多人可能會直接這樣寫:
this->leftup = new point(*other.leftup);
如果你拷貝的other裡的leftup是個空指標呢?我們還在堆裡建立他幹嘛?
所以這裡要加個if判斷。
if(other.leftup != null)
else
只有建構函式可以這樣
rectangle::rectangle(const rectangle& other)
: shape(other), width(other.width), height(other.height)
在花括號之前這樣直接初始化,賦值操作符是不可以的,這是建構函式才擁有的特例。
所以我們還是老老實實用this指標吧。不過我相信很多人會忘了在開頭寫這句判斷:
if(this == &other)
如果他賦值操作的就是他本身,我們不加判斷的直接進行操作,在處理leftup的時候,
this->leftup = new point(*other.leftup);
已有的other.leftup被再次指向了乙個新的point物件,但你原來的的other.left並沒有被銷毀,原來的資料不再被記錄在案,換句話說你搞丟他了,這樣便出現了記憶體洩露。
不過不用驚訝,***說「大部分程式設計師的c++程式裡必然會出現記憶體洩露的問題」,所以要想成為那少數的「大牛」,就從現在開始養成良好的習慣,學習畫你的資料記憶體模型,搞清楚每乙個資料的動向、聯絡。確保你寫的程式萬無一失。
接下來我們要思考父類shape要怎麼寫呢?
說實話,我對處理繼承的父類的東西是一竅不通的,連上面那個建構函式shape(other)都是看的別人的,看到這個直接歇菜了。我開始寫了個這樣的
shape(other.no);
連我自己都不知道這是什麼鬼,一提筆便暴漏出很多問題來。我們幾個c++都不曉得該怎麼處理,然後有人從網上找了個答案。寫成了醬紫:
shape::operator=(other);
***後來過來看到我們這樣寫還以為我們是懂的,說這是對父類操作符過載的標準寫法。
這裡我們把「operator=」看做乙個整體,即shape的成員函式,然後我們直接傳入引數other,這樣便呼叫了shape的預設建構函式,對no進行的賦值操作,這樣做的好處是我們完全不必管shape內部是如何實現的,以及是否發生改動,我們只管做我們的賦值操作就ok了。
今天***講的時候,提到了過了很多次這個思想,你這個函式定義的什麼功能就只做什麼事情,不要直接」left->x = x」,搞得你很懂外面那個類是怎麼實現的一樣。很多時候我們在進行團隊合作的時候,尤其是大公司,你呼叫的東西一很可能不是你寫的,你不知道你用的那個資料何時回發生改動,所以你要保證你的通用性,魯棒性。盡量用這種寫法,否則後患無窮。
this->leftup = new point(x, y);
this->leftup = new point(*other.leftup);
shape::operator = (other);
賦值操作的最後我們仍要談到喜歡逗你玩的leftup。
if(other.leftup != null)
else
}else
首先我們要判斷other.leftup是否為空,如果不為空我們就準備進行賦值操作,繼續判斷當前類成員leftup是否為空,若為空就new乙個直接在堆中初始化,否則直接改變leftup指向的內容(原來指向的會被析構函式釋放掉)。最後,若要賦值的other.leftup為空,我們就先delete當前類中的leftup,然後將他指向null。
inline
rectangle& rectangle::operator=(const rectangle& other)
shape::operator = (other);
this->width = other.width;
this->height = other.height;
if(other.leftup != null)
else
}else
return *this;
}
inline
rectangle::~rectangle()
測試知識回顧
輾轉幾年過去了,學習都是日積月累的,抽時間複習一下基礎知識。一.什麼是軟體測試。1.發現缺陷 2.節約成本,減少風險。3.以使用者需求為基準 二.6大特性 1.功能性2.效率性 3.可移植性4.可維護性5.可靠性 6.易用性 功能性 1.適應性2.準確性3.互操作性4.保密安全性5.依從性 可靠性 ...
回顧測試和測試方法
軟體生命週期 測試過程 記住開發模型 測試模型 v w h模型總結 v模型適用於中小企業。w模型適用於中大型企業,因為對於專案組成員要求高。h模型對專案組成員要求非常高,很少有公司採用。測試分類 按照手工 自動化來分 按照測試物件來分 單元測試 被測程式的最小單元,函式或者類 整合測試 有若干單元組...
回顧關於遊戲測試
不知不覺,在網際網路已經跨入了1個整數的年頭了。逃避荒廢過,也把自己當壓縮餅乾一樣,瘋 活了幾年。這些年我換了好幾個崗位,程式,測試,策劃,產品。這點我自己也比較糾結,還好測試是做的最久的,也給我帶來一些乙份耕耘必然有乙份收穫滿足感。這些年做遊戲,也並沒有荒廢掉網際網路的一些知識。也是因機緣巧合,在...