1. 程式人生 > >C++學習筆記-----在一個建構函式中呼叫另一個建構函式

C++學習筆記-----在一個建構函式中呼叫另一個建構函式

在建構函式中呼叫另一個建構函式如果一不注意就會有無限遞迴的危險,而且建構函式的引數的不同也決定了呼叫的不同,所以特意總結了一下哪些形式的呼叫時允許的:

首先假設建構函式呼叫時引數都是外部的變數,而不是一個常量。

第一種,也是C++11支援的一種呼叫方式。在函式的初始化列表中呼叫另一個建構函式:

int b = 2;
class Test
{
public:
	Test() : Test(b) {} //在初始化列表呼叫Test(int a)
	Test(int a) : p(a) {}
	~Test() {}

	int get() { return p; }
private:
	int p;
};


第二種,用this指標顯示呼叫建構函式:

int b = 2;
class Test
{
public:
	Test()
	{
		this->Test::Test(b);//通過this指標顯式呼叫Test(int a)
	}
	Test(int a) : p(a) {}
	~Test() {}

	int get() { return p; }
private:
	int p;
};

這種方法一定不能忘記加上作用域,不然編譯無法通過!

第三種,在原始記憶體覆蓋:

int b = 2;
class Test
{
public:
	Test()
	{
		new (this) Test(b);
	}
	Test(int a) : p(a) {}
	~Test() {}

	int get() { return p; }
private:
	int p;
};

使用new (void*p) Type(...),這種語句的意思是不重新分配記憶體,而是直接覆蓋在原記憶體上。就本例而言,定義一個Test型別的變數覆蓋在this地址指向的記憶體上。

上述三種都在對this指向的物件進行操作,如果是想在建構函式中定義一個同類型的變數,需要使用花括號而不是圓括號傳參:

int b = 2;
class Test
{
public:
	Test()
	{
		Test{ b };//使用花括號{}
	}
	Test(int a) : p(a) {}
	~Test() {}

	int get() { return p; }
private:
	int p;
};

另一種方法是顯式指出型別:

int b = 2;
class Test
{
public:
	Test()
	{
		Test((int)b);//顯式指出型別
	}
	Test(int a) : p(a) {}
	~Test() {}

	int get() { return p; }
private:
	int p;
};

這兩種都不會無限遞迴,但是隻是建立了一個區域性變數,建構函式結束的時候這個區域性變數會被銷燬。

另外需要注意的是,如果把變數b換成常量2,使用Test(2)不用造成無限遞迴,會正確執行。

如果編譯器支援C++11,那麼比較推薦的方法是使用初始化列表來呼叫其它建構函式。