說明:
? <u>不是很清楚的點</u>,用下劃線婉烟。
? 解答洼冻,用斜體;
? 重點隅很,用粗體加粗撞牢;
第二章 Data 語意學(xué)
3.2 Data Member 的布局
非靜態(tài)成員變量在class object中的排列順序?qū)⒑推渎暶鞯捻樞蛞粯拥摹5獵++ standard允許編譯器將多個access sections之中的data members自由排列叔营,不必在乎他們的出現(xiàn)在class中的聲明順序屋彪。
3.3 Data Member 的存取
存取代價:
每一個member 的存取許可(private public protected),以及與class的關(guān)聯(lián)绒尊,并不會導(dǎo)致任何空間上或執(zhí)行時間上的額外負(fù)擔(dān)——不論是在個別的class objects 或是在static data member 本身畜挥。
static data members:
靜態(tài)數(shù)據(jù)成員(static data members) 被視為global變量,只有一個實體婴谱,存放在程序的data segment(數(shù)據(jù)段)之中蟹但,每次取static member 就會被內(nèi)部轉(zhuǎn)化為對該唯一的extern 實體的直接參考操作躯泰。若取一個static data member的地址,會得到一個數(shù)據(jù)類型的指針华糖,而不是只想起class member的指針麦向。
nonstatic data members:
只要程序猿在一個成員函數(shù)中直接處理一個非靜態(tài)成員變量,“隱式類對象(this指針)”就會出現(xiàn)客叉。
欲對一個nonstatic data member 進(jìn)行存取操作诵竭,編譯器需要把this指針(class object的起始地址)加上data member的偏移量。
非靜態(tài)成員變量的偏移量在編譯時期就可以獲知兼搏,即使這個成員變量是屬于被派生的類卵慰。因此存取效率高。
3.4 繼承 與 Data Member
class Point2d{
public:
//....
private:
float x,y;
}
class Point3d{
public:
//....
private:
float x,y,z;
}
討論上述結(jié)構(gòu)佛呻,與 “提供繼承結(jié)構(gòu)” 有什么不同裳朋?
下面分四種情況討論。
1.只要繼承不要多態(tài)
具體繼承(相對于虛擬繼承)并不會增加空間或存儲時間上的額外負(fù)擔(dān)吓著。這種情況base class和derived class的objects都是從相同的地址開始鲤嫡,其差異只在于derived object 比較大,用以容納自建的靜態(tài)數(shù)據(jù)成員夜矗,把一個derived class object指定給base class 的指針或引用(一定要通過指針或引用)泛范,并不需要編譯器去調(diào)腿门埃或修改地址紊撕,提供了最佳執(zhí)行效率。
2.加上多態(tài)
即在繼承關(guān)系中赡突,提供一個虛函數(shù)接口对扶。
多態(tài)帶來了程序彈性,但這種彈性會帶來空間和存取時間的額外負(fù)擔(dān):
- 導(dǎo)入一個虛函數(shù)表 惭缰,用來存儲它所聲明的每一個virtual functions的地址浪南。
- 在每一個class object中導(dǎo)入一個vptr,提供執(zhí)行期的鏈接漱受,使每一個object能夠找到相應(yīng)的virtual table络凿。
- 加強constructor,使它能夠為vptr設(shè)定初始值昂羡,讓它指向class 所對應(yīng)的virtual table 絮记。
- 加強destructor,使它能夠消抹“指向class 相關(guān)virtual table”的vptr虐先。
3.多重繼承
class point2d{
public:
//....
protected:
float x,y;
}
class Vertex{
public:
//....
protected:
Vertex *next;
}
class Vertex3d: public point2d, public Vertex{
//point2d是第一個base class怨愤,Vertex是第二個
public:
//....
protected:
float mumble;
}
對于一個多重派生對象,將其地址指定給“最左端(第一個)base class的指針”蛹批,情況和單一繼承時相同撰洗,因為二者都指向了相同的起始地址篮愉;至于第二個或后面的base class 的地址指定操作,則需要將地址修改過:加上(<u>或減去差导,如果是downcast</u>)介于中間的base class subobject(s)的大小试躏。
如果要存取第二個(或后面)的base class 中的一個data member ,會增加額外的成本嗎柿汛?不需要付出額外的成本冗酿,因為members的位置在編譯時期就固定了,因此存取member只是一個簡單的offset的運算络断。
4.虛擬繼承
這一部分比較難裁替,并且各個編譯器實現(xiàn)方式不同。
class如果含有一個或多個 virtual base class subobjects 將被分割為兩部分:一個不變區(qū)域和一個共享區(qū)域貌笨。
- 不變區(qū)域中的數(shù)據(jù)弱判,不管后繼如何衍化,總是能有固定的offset锥惋,這部分可以被直接存炔;
- 至于共享區(qū)域膀跌,所表現(xiàn)的就是virtual base class subobject 遭商,這個部分?jǐn)?shù)據(jù),其位置因為每次派生操作而有變化捅伤,所以只能間接存取劫流。