Data語意學
class X{};
class Y : publicvirtual X {};
class Z : publicvirtual X {};
class A : publicY, public Z {};
sizeof(X) = 1,sizeof(Y) = 4, sizeof(Z) = 4, sizeof(A) = 8;visualc++6.0上測試結果(對emptyvirtual base class 有特殊處理的編譯器)
反之則對應的結果為1,8,8,12
事實上Y,Z的大小受三個因素的影響:
1.語言本身所造成的額外負擔
2.編譯器對於特殊情況所提供的優化處理
3.Alignment限制
有特殊處理情況下對象布局如下:
無特殊處理情況對象布局如下:
對於nonstaticdata members直接存放在每一個classobject之中。對於繼承而來的nonstatic data members也是一樣,不過並沒有強制定義其間的排列順序。至於staticdata members,則被放置在程序的一個globaldata segment中,不會影響個別的classobject的大小。
一Data Member的綁定
1.Datamembers綁定
extern int x;
class Point3d
{
public:
//對函數本身的分析將延遲至class聲明的右邊大括號出現才開始
float X() const { return x;}
//....
private:
float x;
};
對memberfunctions本身的分析,會直到整個class的聲明都出現了才開始即對於X()函數返回的x將是類中的定義的x。
2.Membersfunctions的argumentlist
typedef int length;
class Point3d
{
//typedef char length;
public:
//length被決議為global
//_val被決議為Point3d::_val
void mumble(length val) { _val = val; }
length mumble() {return _val;}
private:
//length必須在“本class對它的第一個參考操作”之前被看見
//這樣的聲明將使先前的參考操作不合法
typedef char length;
length _val;
};
上述的這種語言狀況,仍然需要某種防御性程序風格:情始終把“nestedtype聲明”放在class的起始處。
二Data Member的布局
Nostatic data members 在classobject中的排列順序將和其被生命的順序一樣,任何中間介入的staticdata members都不會被放進對象布局之中。
C++ standard要求,在同一個accesssection(也就是private、public、protected等區段)中,members的排列只需符合“較晚出現的members在classobject中有較高的地址”這一條件即可。
C++ standerd也允許編譯器將多個accesssection之中的data members自由排列,不必在乎它們出現在class聲明中的次序。
值得注意的是accesssection的多寡並不會招來額外的負擔。例如在一個section中聲明8個members,或是在8個section中總共聲明8個members,得到的object大是一樣的。
三Data Member的存取
1.Staticdata members
存取staticmembers並不需要通過class object;若取一個staticdata memb的
地址,會得到一個指向其classmember的指針,因為static member並不內含在一個classobject中。例如:
&Point3d::chunkSize;
會得到類型如下的內存地址:
const int*
2.NonstaticData Members
Nonstatic data members 直接存放在每一個classobject之中。除非經由明確
(explic)的或暗喻(implicit)的classobject,沒有辦法直接存取它們。在member function 裡面編譯器會自動合成this指針。欲對一個nonstaticdata member進行存取操作,編譯器需要把classobject的起始地址加上data member的偏移量(offset),每一個nonstaticdata member的offset在編譯時期即可獲知。
Point3d origin, *pt;
Origin.x = 0.0;
pt->x = 0.0;
兩種存取方式有什麼重大的差異?答案是“當Point3d是一個derivedclass,而在其繼承結構中有一個virtual base class,並且被存取的member(例如本例中的x)是一個從該virtualbase class繼承而來的member時,就會有重大的差異。
四繼承與Data member
1.只有繼承沒有多態
在c++繼承模型中,一個derivedclass object所表現出來的東西,是其自己的members加上其baseclass members的總和。至於derivedclass members 和baseclass members的排列次序並沒有強制指定,一般是基類在前。
把原本不相干的兩個class湊成一對“type/subtype”會犯的錯誤有:1.可能會重復設計一些相同操作的函數;2.把一個class分解為兩層或更多層,有可能會為了“表現class體系之抽象化”而膨脹所需空間。C++語言保證“出現在derived class中的baseclass subobject有其完整原樣性”。
class Concrete
{
private:
int val;
char c1;
char c2;
char c3;
};
sizeof(Concrete)= 8
將Concrete分裂為三層結構:
class Concrete1
{
Public:
//….
Private:
int val;
char bit1;
};
class Concrete2
{
Public:
//….
Private:
char bit2;
};
class Concrete3
{
Public:
//….
Private:
char bit3;
};
可以得出sizeof(Concrete3)=16,比原先設計的多了一倍。對象布局如下: