從一道題談C++中建構函式調用建構函式

來源:互聯網
上載者:User
#include <stdlib.h>
#include <iostream>
using namespace std;

class CLS
{
public:
int m_i;
CLS( int i ) : m_i(i){}
CLS()
{
CLS(0);
}
};
int main()
{
CLS obj;
cout << obj.m_i << endl;

system("PAUSE");
return 0;
}

列印結果是不定的,不一定為0

代碼奇怪的地方在於建構函式中調用了自己的另一個建構函式

我們知道,當定義一個對象時,會按順序做2件事情:
1)分配好記憶體(非待用資料成員是未初始化的)
2)調用建構函式(建構函式的本意就是初始化非待用資料成員)

顯然上面代碼中,CLS obj;這裡已經為obj分配了記憶體,然後調用預設建構函式,但是預設建構函式還未執行完,卻調用了另一個建構函式,這樣相當於產生了一個匿名的臨時CLS對象,它調用CLS(int)建構函式,將這個匿名臨時對象自己的資料成員m_i初始化為0;但是obj的資料成員並沒有得到初始化。於是obj的m_i是未初始化的,因此其值也是不確定的

從這裡,我們歸納如下:
1)在c++裡,由於建構函式允許有預設參數,使得這種建構函式調用建構函式來重用代碼的需求大為減少
2)如果僅僅為了一個建構函式重用另一個建構函式的代碼,那麼完全可以把建構函式中的公用部分抽取出來定義一個成員函數(推薦為private),然後在每個需要這個代碼的建構函式中調用該函數即可
3)偶爾我們還是希望在類的建構函式裡調用另一個建構函式,可以按下面方式做:
在建構函式裡調用另一個建構函式的關鍵是讓第二個建構函式在第一次分配好的記憶體上執行,而不是分配新的記憶體,這個可以用標準庫的placement new做到:

    先看看標準庫中placement new的定義

inline void *__cdecl operator new(size_t, void *_P)
{
return (_P);
}

可見沒有分配新的記憶體。

正確的方式:

class CLS
{
public:
int m_i;
CLS( int i ) : m_i(i){}
CLS()
{
new (this)CLS(0);
}
};

另: 若建構函式調用自身,則會出現無限遞迴調用,是不允許的

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.