掌握類和對象
---本文是基於大家已經知道類和對象的基礎上強化一些知識
對象構造:
在棧上使用構造函數唯一正確的方法:
ClassName myclass(5);
在堆上使用構造函數:
ClassName *myclass = new ClassName(5);
在棧上聲明對象就會調用其構造函數,而在堆上可以聲明一個類的對象指針,不必立即調用構造函數。
在棧上調用默認構造函數要去掉構造函數的小括號。
一旦自己定義了構造函數,系統就不會自動生成默認構造函數了。
即如果沒有顯式得定義構造函數,系統會自動生成一個默認構造函數(0參數構造函數)
如果沒有顯式得定義拷貝構造函數,系統會自動生成一個按值傳遞的拷貝構造函數。
定義構造函數時,盡量使用初始化列表,警告:數據成員會按其出現在類定義中的順序得到初始化,而不是按照初始化列表中的順序。
如果函數或類方法中不會改變參數的值,則盡量使用const 引用來傳遞參數。
對象撤銷:
如果沒有析構函數,系統會自動生成一個析構函數。
對於棧上的對象,一旦出了作用域,則對象會調用析構函數撤銷對象。
所以不要返回函數或者類方法中定義的對象的引用。
對象賦值:
如下面:
SpreadsheetCell myCell(5),antherCell;
antherCell = myCell;
你可能想說myCell被“復制”到antherCell。不過,在C++世界中,“復制”只會在對象初始化才會出現。如果一個對象已經有值了,而這個值要被重寫或覆蓋。,更准確地說是“賦值”。C++為復制操作提供的是拷貝構造函數。由於拷貝構造函數是一個構造函數,因此只能用於對象創建,而不能用於以後對對象的賦值操作了。因此C++為賦值操作提供的是賦值操作符=重載。如果你沒有自己定義一個賦值操作符,則系統會自動生成一個默認的賦值操作符=,它與默認拷貝行為幾乎完全等同。不過不同與拷貝構造函數的是,賦值操作符會返回對象的一個引用,原因是賦值可以串鏈。
myCell = antherCell = otherCell;
區分賦值和復制:
SpreadsheetCell myCell(5);
SpreadsheetCell antherCell(myCell); //復制(拷貝)構造函數
//也是復制構造函數構造的,沒有調用operator=!,相當於SpreadsheetCell aThirdCell(myCell);
SpreadsheetCell aThirdCell = myCell;
antherCell = myCell; //調用operator=!因為anther已經構造。
綜上:=不一定是調用operator=表示賦值,當用在變量聲明的同一行上時,是復制構造函數的簡寫。
對象作為返回值:
SpreadsheetCell myCell(5);
string s1;
s1 = myCell.getString();
解析:當getString()返回對象myCell的mstringl時,編譯器調用了一個string拷貝構造函數,創建一個匿名的string對象。將這個結果賦值給s1時,會以這個臨時string作為參數,對s1調用賦值操作符。然後這個臨時string對象會被撤銷。
而對於:
SpreadsheetCell myCell(5);
string s1 = myCell.getString();
解析:當getString()返回對象myCell的mstringl時,編譯器調用了一個string拷貝構造函數,創建一個匿名的string對象。然後s1調用拷貝構造函數,而不是賦值操作符。
拷貝構造函數和對象成員:
如果一個對象的成員中還包含其他對象時,,編譯器生成的拷貝構造函數就會遞歸地調用所包含的各個對象的拷貝構造函數。如果你編寫了自己的拷貝構造函數,可以利用初始化列表提供同樣的語義。如果在初始化列表中沒有包含某個數據成員,編譯器會對其完成默認初始化(即調用該對象的0參數默認構造函數),然後才執行構造函數體中的代碼。因此,一旦使用初始化列表,等到執行構造函數體時,所有對象成員已經得到了初始化。
也可以不用初始化列表來編寫拷貝構造函數,如下: www.2cto.com
SpreadsheetCell::SpreadsheetCel(const SpreadsheetCel & src)
{
mValue = src.mValue;
mString = src.mString;
}
此時拷貝構造函數體中為數據成員賦值時,調用的是賦值操作符,而不是數據成員的拷貝構造函數。
摘自 我和我追逐的夢