《C++对象模型》读后感——关于对象

c++对象模型

  C++的对象模型,就是对 C++的新特性所建立的一个模型。简单点来说,它包括对象的内存布局,以及怎么用这个布局。看书上的一个例子:

 1 //C style
 2 typedef struct {
 3     float x;
 4     float y;
 5     float z;
 6 } Point3D;
 7 
 8 //Point3D对象的 operations
 9 Point3D Point3D_constructor(Point3D * const this, float x, float y, float z) {
10   this->x = x;
11   this->y = y;
12   this->z = z;
13   return this;    
14 }
15 
16 void Point3D_print(const Point3D * const pd) {
17     printf("(%g, %g, %g )", pd->x, pd->y, pd->z);
18 }
19 
20 //C++ normal style
21 class Point3D {
22 public:
23   float x;
24   float y;
25   float z;
26 
27   Point3D(float x, float y, float z) : x(x), y(y), z(z) {}
28   void print() const {
29     printf("(%g, %g, %g )", pd->x, pd->y, pd->z);
30   }
31 };
32     

  上面的代码展示了如何在 C 和 C++中实现一个 Point3D。还没有用上继承和虚函数,就可以看出 C++要比 C 语言少写很多代码。但是 C 的代码,我们一看就知道Point3D 需要多少内存,以及内存是如何分布的。而 C++则不一定,下面将讨论3中可能的实现方式。

简单对象模型

typedef struct {
    float *x;
    float *y;
    float *z;
    (*Point3D)(Point3D * const this, float x, float y, float z);
    void (*print)(const Point3D * const this);
} Point3D;

  这个模型最为简单,把 Point3D 的内存想象为一个表,Point3D 的所有 member 都不直接存放在对象中。而是在表的每一个 slot 存放一个指针,指向其 data member 和 method member。存取 data member 和调用 method member,只需要一个表中的索引号即可。这样很容易确定对象的大小,member 数量*指针大小。但是在取得 member 时会多一层间接性,导致性能损耗,并且增大了对象的代销,不能和 C 语言很好的兼容。但是这个概念被用到了指向成员的指针(pointer-to-member)中。

表格驱动对象模型

typedef struct {
    struct Point3D_Data_Members  *p_data[];  //数组的指针
    void *p_method[];
} Point3D;

struct Point3D_Data_Members {
    float x;
    float y;
    float z;
};

void *Point3D_Method_Members[] = {
    &Point3D_constructor,
    &Point3D_print
};

  表格驱动的对象模型,将 data members 和 method members 指针分别放在两张表格中,而对象只需要保存这两张表的地址。这种模型,可以确定对象大小始终为两个指针的大小,但是在取得对象 members 时,仍然需要一层间接性。并且和 C 语言的结构体更不兼容了。但是这个观念被运用到了虚函数中。

C++对象模型

  最后一种模型就和第一处的代码相同了。对象只保存 data members,不保存 method members。成员函数当做普通函数,在使用对象来调用函数时,由编译器调用对应的函数。这样的对象模型是兼容于 C 语言的结构体,不会带来空间的浪费(不用保存成员函数地址,由编译器来调用对应的函数),并且没有那一层间接性,效率上和 C 语言的一样。但是这仅仅是最简单的对象,对于有虚函数和虚继承的对象模型,还要额外的空间和操作来保证这些特性,这些都是编译期可见的。

  1. 如果类的继承体系中有虚函数(自身和基类带有虚函数),则会引入一个虚函数表指针(vfptr)。在 VC 中,通常 vfptr 放在对象开头,导致了对 C 语言的不兼容。
  2. 如果类的继承体系中有虚继承,则会引入一个虚基类表指针(vbptr)。在 VC 中,通常紧接在 vfptr 之后。

 

C/C++中的类型

  这一段和 C++的对象模型没有联系。C/C++是一种强类型的语言,每一种变量都有一个明确的类型,以及此类型支持的操作,如果违反类型的操作,会被编译器报错。但是往下一层到汇编或者机器码,根本就没有 C/C++中类型的概念,只是几种长度的内存和指向某块内存的地址。那么 C/C++中的类型究竟是什么?简而言之,就是类型是编译器用来解释这块内存的标记。假如你把一块4字节的内存定义为一个 int 型,那么编译器就会把它解释为一个 int 型的数据;而把同样一块内存定义为 char[4],编译器就会把它解释为一块存有4个 char 型的内存,你只能在上面调用 char[4]的操作,而不是 int 型的操作。但是 C/C++又支持类型转换,类型转换就是告诉编译器,我想把这块内存当做另一种东西,你以后就换种方式给我解释它。

 

posted @ 2014-03-10 21:34  xien7  阅读(315)  评论(0编辑  收藏  举报