2016-09-04 76 views
3

我有這樣的代碼我試圖瞭解編譯器是如何工作的:構造函數在創建其他類的新對象時如何工作?

#include <iostream> 
using namespace std; 
class Block 
{ 
    int data; 

public: 
    Block(int i = 10) 
     : data(i) 
    { 
     cout << "I just created a Block " << endl; 
    } 
    ~Block() 
    { 
     cout << "I will destroy a Block with " << data << endl; 
    } 
    void inc() 
    { 
     data++; 
    } 
}; 
class A 
{ 
    Block& block1; 
    Block block2; 

public: 
    A(Block& blk) 
     : block1(blk) 
     , block2(blk) 
    { 
     cout << "I just created an A " << endl; 
    } 
    A(const A& a) 
     : block1(a.block1) 
     , block2(a.block2) 
    { 
     cout << "I just created an A by copying but I will also do bad things" << endl; 
     block1.inc(); 
     block2.inc(); 
    } 
    ~A() 
    { 
     cout << "I will destroy an A " << endl; 
    } 
    void inc() 
    { 
     block1.inc(); 
     block2.inc(); 
    } 
}; 
class Fat 
{ 
    A a; 
    A& ra; 
    A* pa; 

public: 
    Fat(A& da) 
     : a(da) 
     , ra(da) 
    { 
     pa = new A(da); 
     cout << "Fat just created !" << endl; 
    } 
    ~Fat() 
    { 
     delete pa; 
     cout << "Fat to be destroyed !" << endl; 
    } 
    void inc() 
    { 
     a.inc(); 
     ra.inc(); 
     pa->inc(); 
    } 
}; 
int main() 
{ 
    Block block; 
    A a(block); 
    Fat fat(a); 
    fat.inc(); 
    return 0; 
} 

在它創建的目的,是創建一個新的塊,或者使用現有的塊? 爲什麼不運行塊的構造函數?

程序的輸出是:

I just created a Block 
I just created an A 
I just created an A by copying but I will also do bad things 
I just created an A by copying but I will also do bad things 
Fat just created ! 
I will destroy an A 
I will destroy a Block with 12 
Fat to be destroyed ! 
I will destroy an A 
I will destroy a Block with 12 
I will destroy an A 
I will destroy a Block with 11 
I will destroy a Block with 15 
+0

您有什麼疑問?引用是引用,值對象不會被複制。 –

+0

「_Why沒有運行塊的構造函數嗎?_」你只調用了它一次'塊塊;'它確實:'我剛剛創建了塊' –

+0

塊1和塊2會有什麼? – Gspoon

回答

2

你可以有更簡單的代碼證明了這一點。

#include <iostream> 

class Noisy 
{ 
public: 
    Noisy() 
     { std::cout << "Noisy default construct\n"; } 
    ~Noisy() 
     { std::cout << "Noisy destroy\n"; } 
}; 

int main() 
{ 
    Noisy noisy1; 
    Noisy noisy2(noisy1); 
} 

輸出

 
Noisy default construct 
Noisy destroy 
Noisy destroy 

即,顯然,只有一個對象構建通知,但有兩個被摧毀。這種明顯不一致的原因是因爲我們沒有記錄全部或我們的構造函數。有一個隱含生成的拷貝構造函數,我們使用的是構建在這一行這裏noisy2

Noisy noisy2(noisy1); 

如果我們定義拷貝構造函數自己,

#include <iostream> 

class Noisy 
{ 
public: 
    Noisy() 
     { std::cout << "Noisy default construct\n"; } 
    Noisy(Noisy const&) 
     { std::cout << "Noisy copy construct\n"; } 
    ~Noisy() 
     { std::cout << "Noisy destroy\n"; } 
}; 

int main() 
{ 
    Noisy noisy1; 
    Noisy noisy2(noisy1); 
} 

輸出:

 
Noisy default construct 
Noisy copy construct 
Noisy destroy 
Noisy destroy 

你可以看到兩個對象是用不同的構造函數構造的。如果你在不同的課程中這樣做,你應該看到類似的結果。您的引用不會被記錄,既不是構造函數也不是析構函數,因爲它們不是對象。

2

當它創建一個A對象,正在創建一個新的塊還是它使用現有的塊?爲什麼不運行塊的構造函數?

看着A構造:

A(Block& blk) 
     : block1(blk) 
     , block2(blk) 
    { 
    } 

block1referenceBlock對象。所以它反映了已經創建的blk變量,它不會創建另一個變量。所以在這種情況下不會調用構造函數。

對於block2這不是真的,這不是一個參考。在那種情況下確實創建了新的對象Block,但是使用copy constructor

您在Block類中定義的內容是默認構造函數。 當從同一類的另一個對象開始創建類實例時,將調用複製構造函數(注意:不是的默認構造函數)。

複製構造函數由編譯器隱式定義,除非您自己定義一個。

例如:

class Block { 
public: 
    Block(const Block& other) : data(oth.data) { 
    std::cout << "Invoked copy 'ctor" << std::endl; 
    } 

    // ... other stuff 
}; 

這就是爲什麼你的代碼調用您的Block類的默認構造函數只有一次。

相關問題