C++的额外成本
C++较之C的最大区别,无疑在于面向对象。类相较于C的struct不仅只包含了数据,同时还 包括了对于数据的操作。在语言层面上C++带来了很多面向对象的新特性,类、继承、多态 等等。新特性使得C++更加强大,但同时却伴随着空间布局和存取时间的额外成本。作为一 个以效率为目标的语言,C++对于面向对象的实现,其实不大,这些额外成本主要由 virtual引起,包括:
- virtual function 机制,用来支持“执行期绑定”。
- virtual base class ——虚基类机制,以实现共享虚基类的 subobject。
除此之外C++没有太多理由比C迟缓。
三种对象模型
C++类包含两种数据成员:静态数据成员和非静态数据成员;同时包含成员函数,静态函数 和虚函数三种成员函数,这些机制在C++对象是如何被表现的?下面有三种模型可以用以表 现它们——简单对象模型、表格驱动对象模型以及C++对象模型。也许你没兴趣去了解有几种 方式可以实现C++的对象模型,只想了解C++对象模型。然则,C++对象模型是在前两种对象 模型上发展而来的,甚至于局部上直接用到前两种对象模型。
假定有一个Point类,我们将用三种对象模型来表现它。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; };
简单对象模型
简单对象模型:一个C++对象存储了所有指向成员的指针,而成员本身不存储在对象中。也 就是说不论数据成员还是成员函数,也不论这个是普通成员函数还是虚函数,它们都存储 在对象本身之外,同时对象保存指向它们的指针。
简单对象模型对于编译器来说虽然极尽简单,但同时付出的代价是空间和执行期的效率.显而 易见的是对于每一个成员都要额外搭上一个指针大小的空间以及对于每成员的操作都增加了 一个间接层。因此C++并没有采用这样一种对象模型,但是被用到了C++中“指向成员的指针” 的概念当中。
表格驱动对象模型
表格驱动模型则更绝,它将对象中所有的成员都抽离出来在外建表,而对象本身只存储指向 这个表的指针。右图可以看到,它将所有的数据成员抽离出来建成数据成员表,将所有的函 数抽取出来建成一张函数成员表,而对象本身只保持一个指向数据成员表的指针。
侯大大认为,在对象与成员函数表中间应当加一个虚箭头,他认为这是Lippman的疏漏之处, 应当在对象中保存指向函数成员表的指针。
然而我在这儿还是保留原书(而非译本)的截图,因为以我之拙见,不保存指向成员函数表 的指针也没有妨碍。因为形如float Point::x()
的成员函数实际上相当于float x(Point*)
类型的普通函数,因此保存指向成员函数表的指针当属多此一举。
当然C++也没有采用这一种对象模型,但C++却以此模型作为支持虚函数的方案。
C++对象模型
所有的非静态数据成员存储在对象本身中。所有的静态数据成员、成员函数(包括静态与非 静态)都置于对象之外。另外,用一张虚函数表(virtual table)存储所有指向虚函数的指 针,并在表头附加上一个该类的type_info对象,在对象中则保存一个指向虚函数表的指 针。如下图:
关于最后一个程序,这里虚函数采用的是索引号的形式
这里正好解释我之前的一个疑问:http://blog.youkuaiyun.com/hellowos/article/details/11854671