標籤:

關於c++ default constructor的問題,這個說法對嗎?

真的沒有一個是真的嗎?在c++ 11標準里,仍然是這樣嗎?例如一個class裡面只有非class 的member object也不繼承,這樣的話就不存在default constructor?我怎麼記得不論如何,default constructor都會生成?

@阿帥哥 的答案是正確的。即便一個{}的構造函數也不會被構造。。


只要有copy constructor,default constructor就不會被合成,所以第一條是錯的。

第二條更不用說了,你放個指針的話初始值不一定是nullptr。


其實最好的辦法還是RTFM……

1.

如果你不定義任何constructor,那麼default constructor是會有的,編譯器自動給你生成一個空的。

如果你定義了其他constructor,但沒有定義default constructor,編譯器也不會再給你生成空的default constructor。

C++11的變化是,這種情況下如果你還想要編譯器給你生成那個空的default constructor,可以用新的=default語法,寫起來更簡便。如果你明確不想要這個constructor,可以用=delete明確禁用,方便編譯器也方便人讀。

也就是說C++11隻是給了你一點語法糖,規則、語義都沒有變化。

2.

C++自動生成的那個空的default constructor只會保證基類的default constructor以及那些class member的default constructor會被調用,其他什麼都不會做。如果你有int,char*這樣的基礎類型,default constructor不會給他們初始化值。

3.

一個類完全可以沒有default constructor,雖然這會給類的用途上帶來限制,但這是語法所允許的。


C++11沒仔細研究過,按之前的標準

當你一個constructor都沒有定義的時候,會有default constructor,沒有參數;當你至少定義了一個的時候就沒有了。

default constructor會調用member的默認構造函數,實際上任何構造函數都會,只要這個member沒有出現在初始化列表裡;但是對int這樣的類型來說,默認構造函數不代表這個欄位會被初始化——它們實際上什麼都不幹,所以欄位的值仍然是沒有初始化的狀態。

可以在初始化列表裡明確指定各個member構造函數的欄位,如果不指定,就會使用member的默認構造函數。如果某個member沒有默認構造函數,還會報編譯錯誤,這種情況下就必須在初始化列表當中顯示指定。


第一個,「任何」不對,有的類沒法生成默認ctor,比如有引用成員的類

第二個,原生類型是不會初始化的


是那本深入理解c++模型嗎?我的理解是,編譯器是否合成default constructor要看是否有必要,這部分內容著重強調虛擬和繼承機制。如果class存在虛函數,父類或者class member,編譯器必須有一個constructor的動作,否則如果是非常簡單的class,只要分配內存就可以了。

初學者,如理解有誤,還請指正


建議看看深度理解C++對象模型這本書,裡面有專門的章節說這兩個問題。

1.第一個問題編譯器不會為有自定義構造函數的class生成default ctor,即使在生成的ctor中也分trival和nontrival。

2.第二個問題,其實可以自己寫個測試類試試啊,編譯器不會幫你把pointer賦值NULL,int賦值0

如有疏漏歡迎指教。


第1條:如果一個類存在任何構造函數都將不再有自動生成的默認構造函數。

C++11的主要不同在於,可以通過= default和= delete強制生成或刪除默認構造函數。

第2條:自動生成的默認構造函數會調用基類(如果有)的默認構造函數,(若該對象非靜態非全局)並對所有數據成員進行默認初始化。默認初始化區別於值初始化,對於基本類型數據成員將初始化為garbage value,對於類類型數據成員則將執行其默認構造函數。

C++11的主要不同在於,對於存在類內初始化的,自動生成的默認構造函數將會依據類內初始值初始化。

以上。(等我回寢室核查一下以上的說法,如有錯誤,望見諒)


考慮這樣一段代碼:

#include &

using namespace std;
class A
{
private:
int num;
public:
int Num() const { return num; }
void Num(int val) { num = val; }
};

class B : public A
{
};

class C
{

private:
int num;
public:
int Num() const { return num; }
void Num(int val) { num = val; }

virtual void Fuck()
{

}

};

為了清晰的表達我的意思,main函數先寫實例化A類的對象a:

A a;
a.Num(1);
cout &<&< a.Num() &<&< endl;

編譯後,用IDA查看編譯後的代碼 (VC++2015 DEBUG)

可以看到此處並沒有調用c++所謂的默認構造,那到底生成了沒有呢?在IDA里搜索A::A字元串,你會發現

Pattern is not found

那是不是我搞錯了呢? 你再搜索A::Num是有的可以精準定位,所以.確實沒有默認構造.

看下一個例子

B b;
b.Num(2);
cout &<&< b.Num() &<&< endl;

代碼中,B只繼承了A,在IDA里搜索A::A或者B::B字元串,仍然是Pattern is not found , 另外反彙編代碼如下:

也說明並沒有調用所謂的默認構造,他壓根就沒有!!!那什麼情況下會有呢?

看第三種情況,有虛函數的情況:

C c;
c.Num(3);
cout &<&< c.Num() &<&< endl;

反彙編代碼:

C類同樣沒有寫構造函數,但是你會發現他卻調用了一個無參構造,這說明這時候確實有了?

為什麼有了?他幹了什麼?

進到C::C();里看下....

簡單的說就是C類實例化對象的時候要填充虛函數表, ??_7C@@6B@ 是當前對象實現Fuck虛函數函數地址

如果你有一個D,繼承C,D的構造函數里會是什麼呢?

class D : public C
{

private:
int num;
public:
int Num() const { return num; }
void Num(int val) { num = val; }

virtual void Fuck()
{
num = 2;
}

};

反彙編:

可以看到,D類的構造函數不光調用了C類的構造函數也還填充了自己的虛函數表PS: 環境VC++2015 x86 DEBUG


default constructor 只有在必須的時候才被填充


送樓主一句話,看書不認真,也不動手寫代碼驗證


effctive c++第七條?

使用初始化列表為啥效率高,不就是因為只調用一次copy,而不是多調用一次構造函數么。

我的回答居然在輪子哥上邊。


推薦閱讀:

c++中的左值跟右值怎麼區分?
語句str2= str1 + (str1.size() - 1," ")為什麼只有1個空格添加進去了?
C++中類B需要訪問類A的私有成員變數,除了將B聲明為A的友元類外還有其它方法嗎?
如何在#define里使用"#"?
繼承模板類為什麼可以用this訪問基類?

TAG:計算機 | C |