學習筆記:構造函數

構造函數是特殊的成員函數,只要創建類類型的新對象,都要執行構造函數。

構造函數的工作是保證每個對象的數據成員具有合適的初始值。

構造函數的名字和類的名字相同,並且不能指定返回類型,像其他任何函數一樣,它們可以沒有形參,也可以定義多個形參。


1.1 構造函數可以被重載


1.2 實參決定使用哪個構造函數


1.3 構造函數自動執行

只要創建該類型的一個對象,編譯器就運行一個構造函數。


1.4 構造函數不能聲明爲const

創建類類型的const對象時,運行一個普通構造函數來初始化該const對象。


2.1 構造函數初始化式

構造函數還可以包含一個構造函數初始化列表:

B(const string &book):m1(book), m2(0), m3(0.0) { }

構造函數初始化列表以一個冒號開始,接着是一個以逗號分割的數據成員列表,每個數據成員後面跟一個放在圓括號中的初始化式。

構造函數初始化式只在構造函數的定義中而不是聲明中制定。

省略初始化列表並在構造函數的函數體內對數據成員賦值是合法的。例如:

B::B(const string &book) {
m1 = "book", 
m2 = 0;
m3 = 0.0;
}

這個構造函數給類B的成員函數賦值,但沒有進行顯示的初始化。不管是否有顯式的初始化式,在執行這個構造函數之前,要先初始化m1,m2,m3。這個構造函數隱式的使用默認的string構造函數來初始化成員變量,所以執行這個構造函數之後,m1,m2,m3被構造函數體中的賦值所覆蓋。

也就是說,定義初始化列表和沒有定義初始化列表的構造函數的區別在於,前者是初始化數據成員,否者是對調用了默認構造函數後的數據成員進行賦值。

沒有默認構造函數的類類型的成員,以及const或引用類型的成員,都必須在構造函數初始化列表中進行初始化。(初始化const或應用類型數據成員的唯一機會是在構造函數初始化列表中。)例如,當成員變量m2的聲明是const int m2;則上面的構造函數是錯誤的,只能用初始化列表。


2.2成員初始化的次序

成員被初始化的次序就是定義成員的次序。例如:

class X {
  int i;
  int j;
public:
   X(int k): j(k), i(j) { }
};

上面的初始化的效果是先用尚未初始化的j來初始化i,接着纔是用初始化j,這樣做通常跟預期的效果是不一樣的,有時是危險的。


3 默認實參與構造函數


4 默認構造函數


4.1 綜合的默認構造函數

只有當一個類沒有定義構造函數時,編譯器纔會自動生成一個默認構造函數。

綜合的默認構造函數初始化成員,具有類類型的成員通過各自的默認構造函數來進行初始化,內置和符合類型的成員,如指針和數組,只對定義在全局作用域的對象才初始化,對定義在局部作用域的內置或複合類型成員不進行初始化。


4.2 類通常應定義一個默認構造函數


4.3 使用默認構造函數

先看一條語句:

B b();

如果我們要聲明用一個默認構造函數初始化的對象,用上面的方法就錯了,編譯器其實認爲這是個函數的聲明,使用默認構造函數正確的聲明方式:

B b;

去掉括號,或者:

B b = B();


4.4 隱式類類型轉換

看以下代碼:

B func(B b) {
  return b;
}
void main() {
  B temp = func(5);
}

func期待的實參類型是B,但是傳遞的確是int類型,這裏編譯器使用int的構造函數生成一個新的臨時的B對象傳遞給func函數。也就是將5隱式的轉換成了B對象。

通過在構造函數前添加關鍵字explicit可消除這種隱式轉換。


4.5 類成員的顯式初始化

對於沒有定義構造函數並且其全體數據i成員均爲public的類,可以草用與初始化數組元素相同的方式初始化其成員,例如:

struct Data {
  int ival;
  char *ptr;
}
Data val1 = { 1024, "abcde" }









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章