[读书笔记] - 《深度探索C++对象模型》第1章 关于对象

1.C++在布局以及存取时间上主要的额外负担是由virtual引起,包括:

1>virtual function机制:用以支持一个有效率的“执行期绑定”(runtime binding).

2>virtual base class: 用以实现“多次出现在继承体系中的“base class, 有一个单一而被共享的实体”。

 

2.在C++中,有两种class data members: static和nonstatic,以及三种class member functions: static、nonstatic和virtual。

 

3.C++对象模型。在此模型中,Nonstatic data members被置于每一个class object之内,static data members则被存放在所有的class object之外。Static和non static 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 identificatio,RTTI)也经由virtual table被指出来,通常是放在表格的第一个slot处。

class Point
{
public:
    Point(flot xval);
    virtual ~Point();

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

protected:
    virtual ostream& print(ostream& os) const;
    float _x;
    static int _point_count;
};

 

4.虚拟继承。

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

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

在虚拟继承的情况下,base class不管在继承串链中被派生(derived)多少次,永远只会存在一个实体(称为subobject)。例如iostream之中就只有virtual ios base class的一个实体。

 

5.C++中凡处于同一个access section的数据,必定保证以其声明次序出现在内存布局当中。然后被放置在多个access sections中的各笔数据,排列次序就不一定了。

 

6.C++以下列方法支持多态:

1>经由一组隐含的转化操作。例如把一个derived class指针转化为一个指向public base type的指针:

shape *ps = new circle();

2>经由virtual function机制:

ps->rotate();

3>经由dynamic_casttypeid运算符:

if ( circle* pc = dynamic_cast<circle*>(ps) ) 
    ...

 

7.需要多少内存才能够表现一个class object? 一般而言要有:

1>其nonstatic data members的总和大小;

2>加上任何由于alignment的需求而填补(padding)上去的空间(可能存在于members之间,也可能存在于集合体边界);

3>加上为了支持virtual而由内部产生的任何额外负担(overhead)。

 

8.指针的类型。一个指向ZooAnimal的指针是如何地与一个指向整数的指针或一个指向template Array(如下,与一个String一并产生)的指针有所不同呢?

ZooAnimal* px;
int* pi;
Array<String>* pta;

以内存需求的观点来说,没有什么不同。它们三个都需要有足够的内存来放置一个机器地址(通常是个word)。“指向不同类型之各指针”间的差异,既不在其指针表示法不同,也不在其内容(代表一个地址)不同,而是在其所寻址出来的object类型不同。也就是说,“指针类型”会教导编译器如何解释某个特定地址中的内存内容及其大小:

1>一个指向地址1000的整数指针,在32位机器上,将涵盖地址空间1000~1003;

2>如果String是传统的8-bytes(包括一个4-bytes的字符指针和一个用来表示字符串长度的整数),那么一个ZooAnimal指针将横跨地址空间1000~1015(4+8+4)

那么,一个指向地址1000而类型为void*的指针,将涵盖怎样的地址空间呢?是的,我们不知道!这就是为什么一个类型为void*的指针只能够含有一个地址,而不能够通过它操作所指之object的缘故。

所以,转型(cast)其实是一种编译器指令。大部分情况下它并不改变一个指针所含的真正的地址,它只影响“被指出之内存的大小和其内容”的解释方式。

 

9.加上多态之后

class Bear: public ZooAnimal
{
public:
    Bear();
    ~Bear();
    // ...
    void rotate();
    virtual void dance();
    // ...
protected:
    enum Dances { ... };
    Dances dances_known;
    int cell_block;
};

Bear b("Yogi");
Bear* pb = &b;
Bear& rb = *pb;

假设Bear object放在地址1000处,一个Bear指针和一个ZooAnimal指针有什么不同?

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

它们每个都指向Bear object的第一个byte,其间的差别是,pb所涵盖的地址包含整个Bear object,而pz所涵盖的地址只包含Bear object中的ZooAnimal subobject。除了ZooAnimal subject中出现过的members,你不能够使用pz来直接处理Bear的任何members,唯一例外是通过virtual机制:

 

10.总而言之,多态是一种威力强大的设计机制,允许你继一个抽象的public接口之后,封装相关的类型。需要付出的代价就是额外的间接性——不论是在“内存的获得”或是在“类型的决断”上。C++通过class的pointers和references来支持多态,这种程序设计风格就成为“面向对象”。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章