文中一系列思考和內容引發自以下問題:
我需要在一個類的構造函數中調用另一個對象的構造函數,並使用this初始化其中的一個引用成員。
主要遇到的問題:
1. 構造函數的初始化列表中能訪問this嗎?
很明顯c++創建一個對象分為兩部分,創建內存和調用構造函數。
顯然在初始化列表中,當前對象占用的內存已經創建好了,ok,this是可以訪問的,只是其中的某些成員是沒有初始化的(因為沒有構造函數還沒執行完,只能說對象是部分有效的)。
那也間接說明一個問題,在構造函數的函數體中使用this是完全可靠的,所有編譯器可以自動初始化的成員都完成了初始化(比如基類的成員、帶有默認構造函數的成員,注意具體初始化順序是由類成員定義順序確定的),但當前類的部分未在初始化列表中初始化的且沒有默認構造函數類成員變量(比如常見的c++內置類型,int、float、指針等)的值是未定義的。
2. 構造函數參數與成員同名
構造函數的形式如下:帶有一個和類成員同名的參數。打印輸出只是為了驗證成員變量是否初始化。
class A { public: A(int a): a(a){cout<<a<<endl;} private: int a; };
由於初始化列表中不能直接出現this,所以編譯器會處理這種重名的情況。也就說,你不能在構造函數的初始化列表中顯式用this做限定符,比如下面代碼是無法通過編譯的:
A:this->a(a){}
3. 如何在一個類的構造函數匯中調用另一個構造函數
構造函數是不允許嵌套調用的,但可以調用不同的重載形式。比如下面代碼:(注意這是一道面試題目)
struct CLS { int m_i; CLS( int i ) : m_i(i){} CLS(){CLS(0);} }; int main() { CLS obj; cout << obj.m_i << endl; return 0; }
輸出是多少?
---------------------------------------------------------------------------
答案是未知,因為m_i是未初始化的變量,是個野值。
"CLS(0);"的語句表示創建一個臨時的CLS對象,並把該對象的成員m_i初始化為0。當前對象的值並沒有初始化。
如果需要實現構造函數類調用另一個構造函數,需要借助於placement new運算符。代碼如下:
struct CLS { int m_i; CLS( int i ) : m_i(i){} CLS() { new (this)CLS(0); } };
如果你對placement new不了解,建議看看c++ primer或者TCPL。
在c++11中可以直接通過委托或繼承構造函數的形式實現上面功能。
struct CLS { int m_i; CLS( int i ) : m_i(i){} CLS():CLS(0){} };
4. 解決方案
寫到這里。我對於構造函數的初始化列表中引用this的情況基本了解,可以用下面代碼解決本文開始提出的問題。
class Context; class Ref { public: Ref(Context&context):context(context){} private: Context &context; }; class Context { public: Context():ref(*this){} private: Ref ref; };
復述下開始的問題:我需要在一個類的構造函數中調用另一個對象的構造函數,並使用this初始化其中的一個引用成員。
類Context會在其構造函數的初始化列表中通過this調用Ref的構造函數。
5. 參考資料
[1] 從一道題談C++中構造函數調用構造函數 http://www.cnblogs.com/chio/archive/2007/10/20/931043.html
[2] c++ 一個構造函數 調用 另一個 構造函數 http://www.cnblogs.com/ayanmw/archive/2012/08/20/2647808.html