程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> c++對象模型之Data布局

c++對象模型之Data布局

編輯:C++入門知識

c++對象模型之Data布局


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,比原先設計的多了一倍。對象布局如下:

\

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved