文章目錄
假如我們這樣簡單的定義一個類
class Arwen{
public : int age;
}
然後執行個體化它 Arwen wen;
雖然看這個類看起來什麼函數也沒有,但是編譯器一般會預設添加4個函數進去,分別是如下4個函數
無參建構函式
解構函式
複製建構函式
重載賦值運算子
無參建構函式
如果你自己顯示寫了建構函式的話編譯器就不再會給你自動添加一個無參建構函式進去了.
另外我們執行個體化一個類對象時,執行的順序是:先調用父類的建構函式,再調用成員變數中的類物件建構函數,最後才調用自己的建構函式.
有類class job{
public:
job(string name){ }
};
class Arwen{
public:
job myJob;
Arwen() :myJob( "developer"){ //如果不在初始化列表中顯式調用job的有參建構函式就會出錯.因為job中沒有自動添加的無構建構函式了
}
}
一個參數建構函式特殊用法
帶一個參數的有參建構函式有個特殊的用法.例如假如類Arwen有建構函式Arwen( int age) { }
則可這樣執行個體化Arwen wen = 25; //等價於Arwen wen(25);
如果你不希望出現上面這種隱式的轉換,則可這樣去寫建構函式
explicit Arwen(int age) { }
這樣一來再出現Arwen wen = 25這樣的寫法編譯器就報錯了.
解構函式
實際上我們一般用建構函式用的多.剩下的三種函數較少用.一般可不這與就讓編譯器就自動添加就行了.
一般是成員變數中有指標時才會需要顯式的寫解構函式,當需要解構函式時一般也需要複製建構函式和重載賦值操作符,這三個基本上是連在一起出現的.
解構函式一般就是釋放記憶體的了,例如:
class Arwen{
int* pNum;
int* pArray;
public:
Arwen(){
pNum = new int(88);
pArray = new int[4];
}
~Arwen(){
delete pNum;
delete[] pArray; //雖然它前面聲明的時候看起來跟pNum一樣,但分配記憶體時實際上是指向一個數組了.
}
另外如果在類繼承層次中一般把解構函式寫成virtual函數.這樣執行個體化不同的類後才能調用正確的解構函式去釋放記憶體.
複製建構函式
複製建構函式實際上就是一種特殊的建構函式,其實也不太特殊,你就把它看成建構函式得了.只不過這個建構函式的參數必須是類對象而已.例如
Arwen(const Arwen& wen){
age = wen.age
}
所以你可以這樣執行個體化時就是調用複製建構函式:
Arwen an;
Arwen wen(an) ;
Arwen wen = an; //會自動轉換成Arwen wen(an);當然如果你閑得蛋痛硬是要把複製建構函式整成explicit Arwen(const Arwen& wen){ }那自然不能這樣用了.只能老實的用Arwen wen(an);
重載賦值操作符
其實重載賦值操符,然後對它調用.作用和複製建構函式非常類似的.複製建構函式是一次完事,用建構函式構造出一個對象,把另一個對象的值全部拷過來.
而賦值操作的話則必須是相當於分兩步完成的.第一步是之前必須是已經執行個體化出一個對象了,然後才能用其他的對象來賦值給它.例如
Arwen& operator= (const Arwen& wen){
age = wen.age;
return *this;
}
於是你這樣操作的時候:
Arwen an;
an.age = 25;
Arwen wen;
wen = an; //這裡就是調用重載的賦值操作符了.如果你直接這樣寫Arwen wen = an;這可不會去調用重載的賦值運算子,而是調用複製建構函式去了.
實際上重載賦值操作符中的參數也可以隨便寫的了,只不過這樣用處一般不大,很少去用了.例如
Arwen& operator=( int num){
age = num;
return *this;
}
你可以這樣用
Arwen wen;
wen = 25; //這裡就是調用重載的賦值操作符