一個對象的構造分兩部分,首先是分配空間,然後初始化。
只要有對象生成,不管是以什麼形式生成,都會調用構造函數進行初始化。
然後下面有個例子,在藍色區域Big類的復制構造函數中,使用初始化列表進行成員的初始化(方法1)沒有問題,而如果不使用初始化列表、直接在函數裡用裡面注釋掉的代碼(方法2)則會報錯:Base類沒有合適的構造函數。
// W3-課程作業2-4.cpp : Defines the entry point for the console application. #include "stdafx.h" //下面程序的輸出結果是: //5, 5 //5, 5 //請填空: #include錯誤的原因如下。using namespace std; class Base { public: int k; Base(int n) :k(n) { } }; class Big { public: int v; Base b; // 在此處補充你的代碼 //Big ________________{} //Big ________________{} Big(int n) :v(n), b(n) {} Big(const Big& a) :v(a.v), b(a.b) { //v = a.v; //b = a.b; } }; int _tmain(int argc, _TCHAR* argv[]) { Big a1(5); Big a2 = a1; cout << a1.v << "," << a1.b.k << endl; cout << a2.v << "," << a2.b.k << endl; system("pause"); return 0; }
構造一個對象時,先要構造這個對象的每一個屬性,然後再執行該對象構造函數內部的語句。
初始化列表,其實是定義了如何構造每個屬性。而初始化列表中沒有列出的屬性值,則是按照默認的方法初始化。
因此,對於這個例子而言:
方法1使用初始化列表:采用初始化列表中的b(a.b)構造Base類對象b,即調用了合成的復制構造函數,沒有問題;
方法2不使用初始化列表:由於b的構造方法並沒有在初始化列表中說明,因此在執行構造函數之前,需要先調用無參構造函數產生一個Base對象b,而這個無參構造函數並不存在,從而產生錯誤。
另外,之前以為方法2那樣,執行b=a.b;時會調用合成的復制構造函數(即使是這樣,b也還是沒有合適的構造函數初始化。這條語句的時候已經是賦值,而不是初始化),事實上這句是賦值,調用的當然不是復制構造函數,而是執行合成賦值操作符(與合成復制構造函數類似)。這裡把概念弄清楚,以後會少犯混的。
顯示方式。即在初始化列表中,指明 成員基類對象(基類對象) 這樣的方式調用基類的構造函數隱式方式。即不指明,自動得調用基類的默認構造函數。(你要確保基類有默認構造函數,否則出錯)
必須對任何 const 或引用類型成員、以及沒有默認構造函數的類類型的成員使用初始化列表。
(記住,可以初始化const對象或引用類型的對象,但不能對它們賦值。在開始執行構造函數的函數體之前,要完成初始化。
初始化const或引用類型數據成員的唯一機會是在構造函數初始化列表中。)
成員被初始化的次序就是聲明成員的次序。與構造函數初始化列表無關。(消亡順序和聲明順序相反,忘了哪看的了。)
當用於類類型對象時,初始化的復制形式和直接形式有所不同。直接初始化直接調用與實參匹配的構造函數,復制初始化總是調用復制構造函數。復制初始化首先使用指定構造函數創建一個臨時對象,然後用復制構造函數將那個臨時對象復制到正在創建的對象。所以,直接初始化效率高些。
內置類型變量的初始化 全局變量初始化為0,局部變量初始化不進行自動初始化,我覺得靜態變量應該也是初始化為0
定義,用於為變量分配存儲空間,還可以為變量指定初始值。變量有且僅有一次定義。
聲明,用於向程序表明變量的類型和名字(標識符)。變量可以聲明多次。
定義也是聲明,當定義變量時我們聲明了它的類型和名字。
可以通過使用extern關鍵字聲明變量而不定義它。extern聲明不是定義,也不分配存儲空間,它只是說明變量定義在程序的其他地方(文件)。
只有當聲明也是定義時,聲明才可以有初始化式,因為只有定義才分配存儲空間。初始化式必須要有存儲空間來進行初始化。如果聲明有初始化式,那麼它可被當作是定義,即使聲明標記為extern。
且只有當extern聲明位於函數外部時,才可以含有初始化式。