程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 《深度探索C++對象模型》讀書筆記(1)

《深度探索C++對象模型》讀書筆記(1)

編輯:關於C++

在C++中,有兩種class data members:static和nonstatic,以及三種class member functions: static、nonstatic和virtual.已知下面這個class Point聲明:

class Point ...{
public:
Point(float xval);
virtual ~Point();

float x() const;
static int PointCount();

protected:
virtual ostream& print(ostream &os) const;

float _x;
static int _point_count;
};

在 Stroustrup當初設計的C++對象模型中,Nonstatic data members被配置於每一個class object之內, static data members則被存放在所有的class object之外。Static和nonstatic function members也被 放在所有的class object之外,Virtual functions則以兩個步驟支持之:

(1)每一個class產 生出一堆指向virtual functions的指針,放在表格之中,這個表格被稱為virtual table(vtbl)。

(2)每一個class object被添加了一個指針,指向相關的virtual table.通常這個指針被稱為 vptr.vptr的設定(setting)和重置(resetting)都由每一個class的constructor、destructor和copy assignment運算符自動完成。每一個class所關聯的type_info object(用以支持runtime type identification,RTTI)也經由virtual table被指出來,通常是放在表格的第一個slot處。

***虛 擬繼承***

繼承關系也可以指定為虛擬(virtual,也就是共享的意思):

class istream : virtual public ios ...{ ... };
class ostream : virtual public ios ...{ ... };
class iostream : public istream,public ostream ...{ ... };

在虛擬繼承 的情況下,base class不管在繼承串鏈中被派生(derived)多少次,永遠只會存在一個實體(稱為 subobject)。例如iostream之中就只有virtual ios base class的一個實體。

***指針的類型 ***

下面有一個ZooAnimal聲明:

class ZooAnimal ...{
public:
ZooAnimal();
virtual ~ZooAnimal();

// ...
virtual void rotate();

protected:
int loc;
String name;
};

一個指向類的指針與 一個指向整數的指針或一個指向template Array的指針之間的差異既不在其指針表示法不同,也不在於 其內容(代表一個地址)不同,而是在其所尋址出來的object類型不同。也就是說,“指針類型 ”會教導編譯器如何解釋某個特定地址中的內存內容及其大小:

1.一個指向地址1000的整 數指針,在32位機器上,將涵蓋地址空間1000~1003.

2.如果String是傳統的8-bytes(包括一個 4-bytes的字符指針和一個用來表示字符串長度的整數),再加上指向vtbl的指針vptr,那麼一個 ZooAnimal指針將橫跨地址空間1000~1015(4+8+4)。

假設Bear繼承於ZooAnimal,如下所示:

Bear b;
ZooAnimal *pz = &b;
Bear *pb = &b;

一個 Bear指針和一個ZooAnimal指針雖然都指向Bear Object的第一個byte,但pb所涵蓋的地址包含整個Bear Object,而pz所涵蓋的地址只包括Bear Object中的ZooAnimal subobject.

除了ZooAnimal subobject中出現的members,你不能夠使用pz來直接處理Bear的任何members.唯一例外是通過virtual機 制。

// 不合法:cell_block不是ZooAnimal的一個member
// 雖然我們知道pz當前 指向一個Bear object
pz->cell_block;

// ok: 經過一個明白的downcast操作就 沒有問題!
((Bear*)pz)->cell_block;

// 下面這樣更好,但它是一個run-time operation(成本較高)
if(Bear* pb2 = dynamic_cast<Bear*>(pz))
pb2- >cell_block;

// ok: 因為cell_block是Bear的一個member
pb- >cell_block;

***切割引起的編譯器仲裁***

Bear b;
ZooAnimal za = b;  // 這會引起切割(sliced)
// 調用 ZooAnimal::rotate()
za.rotate ();

為什麼rotate所調用的是ZooAnimal實體而不是Bear實體?此外,如果初始化函數( 應用於上述assignment操作發生時)將一個object內容完整拷貝到另一個object中去,為什麼za的vptr 不指向Bear的virtual table?

第二個問題的答案是,編譯器在(1)初始化及(2)指定 (assignment)操作之間做出了仲裁。編譯器必須確保如果某個object含有一個或一個以上的vptrs,那 些vptrs的內容不會被base class object初始化或改變。

至於第一個問題的答案是:za並不是( 而且絕對不會是)一個Bear,它是(並且只能是)一個ZooAnimal.多態所造成的“一個以上的類型 ”的潛在力量,並不能夠實際發揮在“直接存取objects”這件事情上。

***面 對對象(OO)和基於對象(OB)***

基於對象的數據類型可以展示封裝的非多態形式,但是不支 持類型的擴充。一個OB設計可能比一個對等的OO設計速度更快而且空間更緊湊。速度快是因為所有的函 數引發操作都在編譯時期解析完成,對象建構起來時不需要設置virtual機制;空間緊湊則是因為每一個 class object不需要負擔傳統上為了支持virtual機制而需要的額外符合。不過,OB設計比較沒有彈性。

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