c++物件模型之Data布局

來源:互聯網
上載者:User

標籤:c++   資料成員布局   

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,比原先設計的多了一倍。物件版面配置如下:

 

 

 

關於base classsubobject在derivJedclass中保持原樣原因解釋


2.加上多態

多態帶來的空間和存取時間的額外負擔:

①匯入一個virtualtable,用來存放在它所聲明的每一個virtual function的地

址。這個table的元素數目一般而言是被聲明的virtualfunctions的數目,再加上一個或兩個slots。

②在每一個classobject中匯入一個vptr,提供執行期間的連結,使每一個

object能夠找到相應的virtualtable。

③加強constructor,使它能夠為vptr設定初值,讓它指向class所對應的virtual

table。

④加強destructor,使它能夠抹消“指向class之相關virtualtable”的vptr。記

住destructor的調用次序是反向的:從derivedclass到base class。

       所有的編譯器不是吧vptr放在對象的頭部,就是放在對象的尾部。

五指向Data Members的指標

/*

       Pointer to Data Members

*/

#include<iostream>

usingnamespace std;

 

classPoint3d

{

       virtual ~Point3d();

 

public:

       static Point3d origin;

       float x, y, z;

};

intmain()

{

       //類型為floatPoint3d::*而並不是float*

       printf("&Point3d::x =%p\n", &Point3d::x);

       printf("&Point3d::y =%p\n", &Point3d::y);

       printf("&Point3d::z =%p\n", &Point3d::z);

}

 

#include<iostream>

usingnamespace std;

structPoint

{

       int x, y;

       double d1, d2;

}

intAdd(Point arr[], int size, int Point::*p)

{

       int sum = 0;

       for(int i = 0; i < size; i ++)

              sum += arr[i].*p;

       return sum;

}

 

doubleAdd1(Point arr[], int size, double Point::*p)

{

       int sum = 0;

       for(int i = 0; i < size; i ++)

              sum += arr[i].*p;

       return sum;

};

 

intmain()

{

       Point pp[3] = { {1,2,1.0,2.0},{3,4,1.0,2.0}, {5,6,1.0,2.0} };

       cout<<Add(pp, 3,&Point::x)<<endl<<Add(pp, 3, &Point::y)<<endl;

       cout<<Add1(pp, 3,&Point::d1)<<endl<<Add1(pp, 3, &Point::d2)<<endl;

}

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

c++物件模型之Data布局

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.