C++物件模型之二 構造語句 (轉)

gugu99發表於2007-08-16
C++物件模型之二 構造語句 (轉)[@more@] 

C++模型之二 構造語句:namespace prefix = o ns = "urn:schemas--com::office" />

構造

 你是不是這樣認為:

1.  任何類如果沒有定義預設建構函式,就會合成一個;

2.  編譯器合成的會明確設定類中每個資料成員的預設值;

 

事實並非如此的,只有C++編譯器需要的時候才會合成個預設建構函式。

並且在4種情況下會那麼做。

第一種情況:類中帶有物件成員

 class A{……};

 class B

{

 private:

 A a;  //物件成員

 int x;

}

 合成的建構函式

 B::B ( )

 {

a.A::A();

}

假如你定義了個建構函式

A::A ( )

{

x=0;

 }

編譯器會追加程式碼到裡面去

A::A ()

{

  a.A::A();

x=0;

}

第二種情況 基類中有預設建構函式(包括被合成的)

 和第一種一樣,你定義了很多建構函式,編譯器會追加程式碼到每個建構函式中

 

第三種情況 帶有虛擬函式的類 (包括純虛擬函式)

編譯器的必要的操作

1.  一個虛擬函式表將產生,內放虛擬函式的地址;

2.  一個虛擬函式指標將產生,指向虛擬函式表地址;

所以編譯器會為每個物件設定vptr的初始值,放置適當的虛擬函式表地址,對於類所定義的建構函式追加程式碼完成這些事。

 

第四種情況 虛繼承

  class X{publci: int i ; };

  class A :public virtual X { public : int j ;};

  class B: public virtual X { public: double d;};

  class C: public A,public B{ public: int k;};

  void foo(const A *pa) { pa->i=1024;}  //無法在編譯期決定出pa->X::i 的位置

  main() {foo(new A); foo(new C);}  // 可能轉變為 void foo (const A*pa) { pa->_vbcx->i=1024} vbcx是物件指向類X的指標,當然要在建構函式中確定。

複製建構函式

 複製建構函式: 以一個物件的內容去初始化另個物件。 (關鍵在於初始化)

 有三種情況下會複製建構函式

class x {……};

X x;  X xx=x  //不是賦值操作而是複製建構函式

Void foo (X x);  // 物件引數

FooBar() { X x; return x;}  // 返回物件

如果類沒有提供顯示的複製建構函式,編譯器採用的是位逐次複製。也就是把物件資料成員值複製到另個物件上,如果遇到物件成員就會遞迴進去。

class String

{ public:  //類沒有提供顯示的複製建構函式

 private:

char  *str ;

int  len;

};

 

class

{

public:  //類沒有提供顯示的複製建構函式

private:

int occurs;

String str:  //類含了物件成員

}

位逐次複製時先位逐次複製int occurs 遇到word後遞迴進 class String 位逐次複製。

 

當以下情況下編譯器不會採用位逐次複製,而是生成預設的複製建構函式

1.  當類內含一個物件成員,而後者的類中宣告瞭一個複製建構函式時 (包括員寫的,編譯器合成的)

2.  當類繼承一個基類時,而後者存在一個複製建構函式時

3.  當類宣告瞭虛擬函式時

4.  當類派生自一個繼承鏈中有虛繼承時

 

1.當類內含一個物件成員,而後者的類中宣告瞭一個複製建構函式時

class String

{ public:  

String (const char *);

String (const String &)  //類提供顯示的複製建構函式

~String(); 

 private:

char  *str ;

int  len;

};

 

class word

{

public:  //類沒有提供顯示的複製建構函式

private:

int occurs;

String  str:

}

//就會合成一個 : word::word(const word &wd) { str.String::String( wd.str); occurs=wd.occurs;}

2 當類繼承一個基類時,而後者存在一個複製建構函式時

 

class word :public String

{

public:  //類沒有提供顯示的複製建構函式

private:

int occurs;

String  str:

} //就會合成一個

 

3 當類宣告瞭虛擬函式時

class word

{

public:  //類沒有提供顯示的複製建構函式

virtural cout(); //類宣告瞭虛擬函式

private:

int occurs;

String  str:

}  // 同理與建構函式一樣的理由,複製建構函式要處理虛擬函式指標和虛擬函式表。

 

 

4 當類派生自一個繼承鏈中有虛繼承時

class Zoo{…};  class Racconn :public virtual Zoo {….} ;  class ReadPanda : public Racconn {…};

這個時候不是一個類物件要另個類物件做初始化而是基類物件要派生類物件來初始化

Raccoonn rocky;  Racconn little=rocky;  // 簡單的位逐次複製就行了

RedPanda  litteRed;  Racconnn  littecritter = rocky ; 

// 簡單的位逐次複製就不行了,編譯器必須明確地初始化littercritter 虛繼承的指標。

 

 

作者名:曾凡坤, 又名曾牧暗鯊,網名:大白鯊 -7-27

 

 

 

 

 

 

 

 

 

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-960962/,如需轉載,請註明出處,否則將追究法律責任。

相關文章