2.1 Default Constructor 的構(gòu)造操作
??? 按照C++ Annotated Reference Manaual 的說(shuō)法:"Default constructor... 在需要的時(shí)候被編譯器產(chǎn)生出來(lái)". 這里的關(guān)鍵字是:“在需要的時(shí)候”。
??? C++ Standard[ISO-C++95]中又有如下的聲明:對(duì)于class X, 如果沒(méi)有任何user-declared constructor,那么會(huì)有一個(gè)default constructor 被暗中聲明出來(lái)....一個(gè)被暗中聲明出來(lái)的default constructor 將是一個(gè)trival的constructor"。 這里我覺(jué)得主要是“user-declared constructor”,它包括用戶所定義的所有的constructor還有其它的一些有virtual關(guān)鍵字的操作。這樣下面的四種情況下由編譯器生成的constructor是notrival default constructor:
???
??? 1. 帶有 Default Constructor 的 Member Class Object(帶有缺省構(gòu)造函數(shù)的類成員對(duì)象)
??? 如果一個(gè)類的帶有一個(gè)或多個(gè)的類成員對(duì)象,而類成員對(duì)象又有構(gòu)造函數(shù),那么就會(huì)生成該類就會(huì)生成一個(gè)notrival default constructor 構(gòu)造函數(shù)。 成員對(duì)象的構(gòu)造函數(shù)的調(diào)用是按成員對(duì)象的聲明順序執(zhí)行的。例如:
class
?Foo?
{?
public
:?Foo(),?Foo(
int
)?.?}
;

class
?Bar?
{?
public
:?Foo?foo;?
char
?
*
str;?}
;?
??
void
?foo_bar()

{
???????Bar?bar;?
//
?Bar::foo在這里被初始化(調(diào)用Foo的缺省構(gòu)造行數(shù):?Foo:Foo())
??????
??????
//

?????
if
?(str)?
{?}
??.?
???}
????
??? 對(duì)于有多個(gè)成員對(duì)象的類,則按成員對(duì)象在類的聲明中的順序調(diào)用它們的構(gòu)造函數(shù)。
??????
??? 2. 帶有 Default Constructor 的 Base Class(帶有缺省構(gòu)造函數(shù)的基類對(duì)象)????? ?指的是一個(gè)沒(méi)有任何constructorsrs的類派生自一個(gè)帶有“default constructor”的基類。 如果類存在多個(gè)構(gòu)造函數(shù)的話,那么編譯器也會(huì)擴(kuò)充現(xiàn)有的每一個(gè)構(gòu)造函數(shù),將調(diào)用基類的default constructor的代碼加入到其中。
???????
??? 3. 帶有一個(gè) Virtual Function 的 Class
??? 這樣的virtual Function可以使繼承來(lái)的或直接定義的。 編譯器在編譯期間會(huì)做如下工作
??? a. 生成一個(gè)virtual Function talbe(vtbl), 用來(lái)存放class 的virtual function的地址
??? b. 在每一個(gè)class object中,添加一個(gè)額外的pointer member(vptr),它指向class vtbl的地址
???
??? 4. 帶有一個(gè) Virtual Base Class 的 Class
??? 這種情況是在導(dǎo)出類的安插一個(gè)virtual base classes的指針,用來(lái)在運(yùn)行時(shí)存取virtual base class 的成員。例如:
?1?
????class?X?{?public:?int?i;?};?
?2?
????class?A?:?public?virtual?X???{?public:?int?j;?};?
?3?
????class?B?:?public?virtual?X???{?public:?double?d;?};?
?4?
????class?C?:?public?A,?public?B?{?public:?int?k;?};?
?5?
?6?
????//?cannot?resolve?location?of?pa->X::i?at?compile-time?
?7?
????void?foo(?const?A*?pa?)?{?pa->i?=?1024;?}?
?8?
????//?在編譯期可能生成如下形式:
?9?
????//?void?foo(const?A*?pa)?{?pa->_vbcX->i?=?1024;?}?//?_vbcX:?virtual?base?class?X
10?
????
11?
????main()?
12?
????{?
13?
????????foo(?new?A?);?
14?
????????foo(?new?C?);?
15?
????
16?
????????//?
?
17?
????}
18?
19?
????
??? 注意: 在合成的default constructor中,只有base class subobjects和member class objects會(huì)被初始化,其它所有的nostatic data member都不會(huì)執(zhí)行初始化的操作.要我們自己手動(dòng)的去執(zhí)行初始化的操作.
??? 其實(shí)把握一個(gè)原則:要不要合成一個(gè)構(gòu)造函數(shù),依據(jù)編譯器的需要與否,合成出來(lái)的constructor也只是完成那些編譯器所需求。
???
??? 兩個(gè)錯(cuò)誤的觀點(diǎn):
?i. 任何時(shí)候,如果沒(méi)有定義default constructor,就會(huì)被合成一個(gè)出來(lái)。(而是根據(jù)編譯器的需要決定是否生成一個(gè)deault constructor)
?ii. 編譯器生成出來(lái)的default constructor會(huì)明確的初始化每類中的每一個(gè)data member.
2.2 Copy Constructor的構(gòu)建操作
??? 有三種情況下會(huì)有一個(gè)Copy Constructor的操作:
?i.?? 對(duì)一個(gè)object做明確的初始化操作??// class X{ ....};?? X x;??? X xx = x;
?ii.? 當(dāng)某個(gè)object作為參數(shù)傳遞給某個(gè)函數(shù)??// void foo(X x) { .... }
?iii. 函數(shù)傳回一個(gè)class object對(duì)象??// void foo(){ X xx; return xx;}
??? 1. Default Memberwise Initialization(缺省的按成員初始化)
??? 如果一個(gè)類沒(méi)有explicit copy constructor時(shí), class object在執(zhí)行copy constructor時(shí),內(nèi)部以default member initialization的手法來(lái)完成,就是把每一個(gè)內(nèi)建或者派生而來(lái)的data member的值從某個(gè)object 拷貝一份到另一個(gè)object身上,對(duì)member class object是以遞歸的方式調(diào)用memberwise initialization的。
???
??? 這種初始化是通過(guò)在必要時(shí)生成一個(gè)copy constructor或通過(guò) bitwise copy 來(lái)完成的。 如果要通過(guò)bitwise來(lái)完成這這樣的操作,那么必須表現(xiàn)出bitwise copy semantise.?
???
??? C++ Standard中也把copy constructor分成trial 和notrivial兩種類型,只有notrivial的實(shí)體才會(huì)被合成于程序中。決定一個(gè)copy constructor是否為trivial在于類是否表現(xiàn)出所謂的"Bitwise copy sematics".
???
??? 2. Bitwise Copy Semantics
??? 在 bitwise copy sematics 下,不會(huì)構(gòu)造出一個(gè)default copy constructor. 例如:
?
?1?
???class?Word
?2?
????{
?3?
????public:?
?4?
????????Word(const?char*);
?5?
????????~Word(){?delete?[]str;?}
?6?
????????//
?7?
????private:
?8?
????????int?cnt;
?9?
????????char?*str;
10?
????}??
11?
????以上的是一個(gè)表現(xiàn)出Bitwise?copy?sematics的類,而以下是一個(gè)沒(méi)有表現(xiàn)出bitwise?copy?sematics的類
12?
????class?Word
13?
????{
14?
????public:?
15?
????????Word(const?char*);
16?
????????~Word(){?delete?[]str;?}
17?
????????//
18?
????private:
19?
????????int?cnt;
20?
????????String?str;
21?
????}
22?
????
23?
????class?String?
24?
????{
25?
????public:?
26?
????????String(const?char*);
27?
????????String(const?string&);?//?String的顯示copy?constructor
28?
????????~String();
29?
????????//
.
30?
????}
31?
????這種情況下會(huì)合成一個(gè)copy?constructor以調(diào)用class?String?object的copy?constructor.
32?
????inline?Word::Word(const?Word&?wd)
33?
????{
34?
????????str.String::String(wd.str);
35?
????????cnt?=?wd.cnt;
36?
????}????
37?
???????
??? 3. 不表現(xiàn)出Bitwise Copy Sematics的特性的情況
??? 以下的幾種情況class不表現(xiàn)出 Bitwise Sematics:
??????? a. 當(dāng)class 內(nèi)含有一個(gè)member object, 而后者的class 聲明有一個(gè)copy constructor時(shí)(合成或聲明的都可以),就不表現(xiàn)出Bitwise Sematics
??????? b. 當(dāng)class 繼承自一個(gè)base class, 而后者存在有一個(gè)copy constructor(合成或聲明的都可以), 就不表現(xiàn)出Bitwise Sematics.
??????? c. 當(dāng)類聲明了一個(gè)或多個(gè)virtual function時(shí)
??????? d. 當(dāng)class派生自一個(gè)繼承創(chuàng)串鏈,其中有一個(gè)或多個(gè)virtual base classes時(shí), 類就不表現(xiàn)出Bitwise Sematics
??? 這四種情況和default constructor生成的是否一個(gè)trivial是一樣的, 也是滿足編譯器的需求。
??????
??? 4. 重新設(shè)定Virtual Table 的指針
??? 對(duì)于以上:當(dāng)類聲明了一個(gè)或多個(gè)virtual function的情況,程序會(huì)為類對(duì)象做如下兩個(gè)擴(kuò)張操作:
??????? (1) 增加一個(gè)vtbl的指針,內(nèi)含virtual function的指針地址。
??????? (2) 在類對(duì)象內(nèi)安插一個(gè)vptr指針,指向virtual function table.
??? 對(duì)于把一個(gè)base class object 以其derived class object的值初始化操作的時(shí)候,會(huì)發(fā)生切割(sliced)操作。這時(shí)也要保證vtbl的正確和vtpr的正確性。
???
??? 5. 處理Virtual Base Class Subobject
??? 如果一個(gè)class object是以另外一個(gè)object作為初始值的話,而后者又有一個(gè)virtual base class suboject的話,那么也會(huì)使bitwise copy sematics失效。例如:
?1?
????class?Raccoon?:?public?virtual?ZooAnimal{
?2?
????public:
?3?
??Raccoon(){?
?;?}
?4?
??Raccoon(int?val)?{?
;?}
?5?
??private:
?6?
??//?
?7?
????};
?8?
?9?
????class?RedPanda?:?public?Raccoon{
10?
????public:
11?
??RedPanda()?{?
.;?}
12?
??RedPanda(int?val)?{?
.;?}
13?
??private:
14?
??//?
15?
????};
16?
????執(zhí)行如下操作時(shí)會(huì)要求合成一個(gè)copy?constructor:
17?
????RedPanda?little_red;
18?
????Raccoon?little_critter?=?little_re;??//?這里編譯器必須明確的把little_critter的virtual?base?class?pointer/offset初始化。
19?
20?
????//?如果只是這樣的操作用bitwise?copy?就可以了
21?
????Raccoon?rocky;
22?
????Raccoon?little_critter?=?rocky;???//?用簡(jiǎn)單的bitwise?copy?就可以搞定了
23?
24?
2.3 程序轉(zhuǎn)化語(yǔ)義學(xué)(Program Transformation Semantics)
?指的是程序在執(zhí)行的是候要做的類型和操作的轉(zhuǎn)換。 下面例子反映了三種轉(zhuǎn)換操作:
?
?1?
?#include?"X.h"
?2?
?3?
?X?foo(?X?x0)
?4?
?{
?5?
??X?xx;
?6?
?7?
??//?
.,?對(duì)xx和x0進(jìn)行操作
?8?
?9?
??return?XX;
10?
?}
11?
?
?1. 明確的初始化操作(Explicit Initialization)
?例如:
1
X?x0
2
?
void
?foo_bar()
3
?
{
4
??X?x1(x0);
5
??X?x2?
=
?x0;
6
??X?x3?
=
?X(x0);
7
?}
8
?
?對(duì)程序做兩個(gè)階段的轉(zhuǎn)化:
?i. 重寫(xiě)每一個(gè)定義,其中的初始化操作都會(huì)被剝除
?ii. 類的Copy constructor操作會(huì)被安插進(jìn)去
?轉(zhuǎn)化后可能成為這樣的(偽碼):
?這也就是說(shuō)前面三種的初始化操作都會(huì)轉(zhuǎn)換成Explicit Initialization.
?1??void?foo_bar()
?2??{
?3???X?x1;?
?4???X?x2;
?5???X?x3;
?6?
?7???x1.X::X(x0);
?8???x2.X::X(x0);
?9???x3.X::X(x0);
10??}
11?
12?
?2. 參數(shù)的初始化(Argument Initialization)
?例如下面:
?1?
?void?foo(X?x0){?
;?}
?2?
?void?call()
?3?
?{
?4?
??X?xx;
?5?
?6?
??//?
.?xxx?初始化及其操作
?7?
?8?
??foo(xx);
?9?
?}
10?
?轉(zhuǎn)換后的操作為:
11?
?void?call()
12?
?{
13?
??X?xx;
14?
15?
??X?__temp0;
16?
??__temp0.X::X(xx);
17?
??foo(__temp0);????????????????//?foo?函數(shù)應(yīng)變成:void?foo(X&?x0);
18?
??__temp0.X::~X();??
19?
?}
20?
21?
?這就是為什么當(dāng)傳值到孫數(shù)的時(shí)候,不會(huì)把函數(shù)內(nèi)對(duì)傳入值的操作結(jié)果不會(huì)被修改,因?yàn)樗诤瘮?shù)內(nèi)本來(lái)修改的就不是外部傳人的那個(gè)變量。
?3. 返回值的初始化(Return Value Initialization)
?例如:
?X bar()
?{
??X xx;
??// ....
??return xx;
?}?
?
?轉(zhuǎn)化為如下偽碼:
?void bar(X& __result)
?{
??X xx;
??xx.X::X();?? // 編譯器生成的一個(gè)缺省的構(gòu)造函數(shù)調(diào)用
??// 處理 ....
??__result.X::X(xx);??? // 編譯器生成的copy constructor調(diào)用操作
??return;
?}
?
?如下的操作轉(zhuǎn)化為:
?void foo()
?{
??X xx = bar();
?}
?被轉(zhuǎn)化為:
?void foo()
?{
??X xx;
??bar(xx);?? // 注意這里不用執(zhí)行 default constructor
?}
?
?針對(duì)這種轉(zhuǎn)換,可以從使用層面上進(jìn)行優(yōu)化和在編譯器層面上做優(yōu)化操作。在編譯器層面上的操作就是采用NRV(Named Return Value)技術(shù)。
?如:
?x bar()
?{
??X xx;
??// ....
??return xx;
?}
?優(yōu)化為:
?void bar(X& __result)
?{
??__result.X::X();
??//....? 直接的處理 __result
??//
??return ;
?}?
2.4 成員初始化隊(duì)伍(Member Initialization List)
?這里有兩點(diǎn)要注意:
?1. 以下的四種情況下必須使用 member intialization list
??I.?? 當(dāng)初始化一個(gè)reference member時(shí)
??II.? 當(dāng)初始化一個(gè)const member時(shí)
??III. 當(dāng)初始化一個(gè)base class 的constructor,而它擁有一組參數(shù)時(shí)
??IV.? 當(dāng)調(diào)用一個(gè)member class的constructor, 而它擁有一組參數(shù)時(shí)
??其它情況下可以用在構(gòu)造函數(shù)內(nèi)初始化也可以
?
?2. 關(guān)于初始化的次序問(wèn)題:
??編譯器的初始化的順序是按member聲明次序來(lái)依次的初始化的。它會(huì)安插一些代碼到構(gòu)造函數(shù)內(nèi),并放在任何其它用戶初始化的代碼之前.
?