C 基礎 在建構函式內部呼叫建構函式

2022-04-10 11:57:35 字數 1530 閱讀 5564

看下面的面試題:

#include using namespace std;  

struct cls

cls()

};

int main()

列印的結果是系統的乙個隨機值。所以這種直接在建構函式中呼叫另外的乙個建構函式是不可行的。

**奇怪的地方在於建構函式中呼叫了自己的另乙個建構函式

我們知道,當定義乙個物件時,會按順序做2件事情:

1)分配好記憶體(非靜態資料成員是未初始化的)

2)呼叫建構函式(建構函式的本意就是初始化非靜態資料成員)

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

cls obj; 在棧中例項化乙個物件,呼叫預設建構函式

cls obj(10); 在棧中例項化乙個物件,呼叫int引數的建構函式

cls obj(); 這不是例項化物件,這是宣告乙個返回型別為cls,引數為void的函式。當然這個函式宣告可以在其他的函式內部

cls(10); 呼叫int引數的建構函式在棧中產生乙個匿名的物件,類似new cls(10);也是產生匿名的物件,只不過new時要有乙個指標接收這個匿名物件

cls(); 同上,只不過這裡呼叫無參建構函式  

從這裡,我們歸納如下:

1)在c++裡,由於建構函式允許有預設引數,使得這種構造函式呼叫建構函式來重用**的需求大為減少

2)如果僅僅為了乙個建構函式重用另乙個建構函式的**,那麼完全可以把建構函式中的公共部分抽取出來定義乙個成員函式(推薦為private),然後在每個需要這個**的建構函式中呼叫該函式即可

3)偶爾我們還是希望在類的建構函式裡呼叫另乙個建構函式,可以按下面方式做:

當呼叫了乙個類的建構函式,那麼這個類的記憶體一定開闢好了,然後才呼叫建構函式初始化非靜態成員變數的。

在建構函式裡呼叫另乙個建構函式的關鍵是讓第二個建構函式在第一次分配好的記憶體上執行,而不是分配新的記憶體,這個可以用標準庫的placement new做到:

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

inline void *__cdecl operator new(size_t, void *_p)  

從**看來,沒有分配記憶體。

struct cls  

cls()

};

這裡可以看到,new也可以操作棧上已經分配好的記憶體。另: 若構造函式呼叫自身,則會出現無限遞迴呼叫,是不允許的。

所以,在實際使用的時候,單純的在建構函式中呼叫其它的建構函式,只是會產生乙個臨時的匿名變數。如果僅僅是為了重用**,可以把重用的**封裝成乙個新的函式。

C 中構造函式呼叫建構函式

include include using namespace std struct cls cls int main 列印結果是不定的,不一定為0 奇怪的地方在於建構函式中呼叫了自己的另乙個建構函式 我們知道,當定義乙個物件時,會按順序做2件事情 1 分配好記憶體 非靜態資料成員是未初始化的 2 ...

C 中構造函式呼叫建構函式

include stdlib.h include iostream using namespace std struct clscls int main 列印結果是不定的,不一定為0 奇怪的地方在於建構函式中呼叫了自己的另乙個建構函式 我們知道,當定義乙個物件時,會按順序做2件事情 1 分配好記憶體...

c 中構造函式呼叫建構函式

c 中建構函式完成的工作分兩步 1 分配空間 2 初始化空間 構造函式呼叫建構函式。class a a int a private int a 這樣會導致,a 中先分配了空間,然後呼叫a 0 又建立了乙個臨時物件,然後初始化為0,而原物件則沒有初始化。這種問題在類中有指標需要分配空間時會導致災難。從...