当前位置:首页 >> 编程开发 >> Visual C++ >> 内容

《深度探索C++对象模型》读书笔记(1)

时间:2015/5/19 21:37:36 作者:平凡之路 来源:xuhantao.com 浏览:

在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设计比较没有弹性。

相关文章
  • 没有相关文章
  • 徐汉涛(www.xuhantao.com) © 2024 版权所有 All Rights Reserved.
  • 部分内容来自网络,如有侵权请联系站长尽快处理 站长QQ:965898558(广告及站内业务受理) 网站备案号:蒙ICP备15000590号-1