1. 程式人生 > >C++物件模型 第三章 Data語意學

C++物件模型 第三章 Data語意學

1)類的大小
class X{};         
class Y:virtual public X{};
class Z:virtual public X{};
class A:public Y,public Z{};
大小分別為1 4 4 8
下面計算sizeof(A)
class X的大小(“編譯器有無特殊處理”,有特殊處理就是0)
base class y的大小減去“因virtual class X而配置的大小”(4)
base class z的大小減去“因virtual class X而配置的大小”(4)
class A自己的大小(0)
alignment(0)






2)每一個class object必須有足夠大小以容納它所有的非靜態資料成員,它可能比你想象的還大,原因
①編譯器自動加上了額外的data members,支援如virtual 特性
②alignment的需要




3)member rewriting rule:大意是“一個inline函式實體,在整個class宣告未被完全看見之前,是不會被評估求值的”。因此,一個inline member function內部的一個data member繫結操作,會在整個class宣告完成之後才發生。




4)data member layout
非靜態資料成員在class object中的排序將和其被宣告的順序一樣,任何中間介入的static data member都不會被放進物件佈局之中。而存放在程式的data segment中。c++ standard要求members的排列只需符合“較晚出現的members在class object中有較高的地址”


5)data member 存取
point3d origin,*pt=&origin;
origin.x=0.0
pt->x=0.0
通過origin存取和通過pt存取,有什麼的重大的差異嗎?答案是肯定的!
當point3d是一個derived class,而繼承結構中有一個virtual base class,並且被存取的member(本例中的x)是一個從該virtual base class 繼承而來的member時,就會有重大的差異。這時候我們不能夠說pt必然指向哪一種class type(我們不知道編譯時期這個member的真正offset),所以這個存取操作會延遲到執行期,經由一個額外的間接引導,才能解決。但如果使用origin,就不會有這些問題,其型別無疑使point3d class ,而即使它繼承自virtual base class,member的offset在編譯時期也就固定了。




int point3d::*p2=&point3d::x;
point3d::* 的意思是:指向point3d data member的指標型別。所以若取一個static data member的地址,會得到一個指向其資料型別(如int)的指標,而不是一個指向其class member的指標,因為static member並不內含在一個class object之中。




虛擬繼承將為“經由base class subobject”存取class members匯入一層新的間接性。
比如point3d *pt3d;
pt3d->x=0.0
其執行效率在x是一個struct member、一個class member 、單一繼承、多重繼承的情況下是完全相同的。但如果x是一個virtual base class的member,存取速度將會稍慢一點。




6)繼承與 data member
一般而言,具體繼承(相對於虛擬繼承而言virtual inheritance)並不會增加空間或時間上的額外負擔。
在cfront編譯器中,vptr被放置在class object的尾端。這樣可以保留base class C struct的物件佈局,因而允許在c程式程式碼中也能使用。
①單一繼承而且沒有virtual function時的資料佈局
②單一繼承並且含有虛擬函式情況下的資料佈局。
③多重繼承
④虛擬繼承
parent
|
child
|
grandchild


非虛擬繼承:每個父類都有自己的虛表,子類的成員函式被放到了第一個父類的表中。
參見:http://blog.csdn.net/haoel/article/details/1948051
http://blog.csdn.net/haoel/article/details/3081328
http://blog.csdn.net/haoel/article/details/3081385#comments


7)指向 data members的指標
&point3d::z 上述操作將得到z座標在class object中的偏移位置。最低限度值為x和y的大小總和,因此C++語言要求同一個access level中的member的排序順序應該和其宣告順序相同。
鑑於取一個nonstatic data member 會得到它在class中的offset,取一個static data member 會得到真正的記憶體地址。


struct base1{int val1;};
struct base2{int val2;};
struct derived:base1,base2{};


printf("&base1::val1:%p \n",&base1::val1);
printf("&base2::val2:%p \n",&base2::val2);
printf("&derived::val1:%p \n",&derived::val1);
printf("&derived::val2:%p \n",&derived::val2);
結果全為0

為什麼第四個返回的也是0呢,很可能編譯器已經內部處理過了。