C++在布局以及存取时间上主要的额外负担是由virtual引起的,包括:
- virtual function 机制 :用以支持一个有效率的“执行期绑定”(runtime binding)。
- virtual base class :用以实现“多次出现在即成体系中的base class ,有一个单一而被共享的实体”。
此外,还有一些多重继承下的额外负担,发生在“一个derived class 和其第二或后继之base class的转换”之间。然而,一般而言,并没什么天生的理由说C++程序一定比其C兄弟庞大或延缓。
在C++中,有两种class data member:static和nonstatic,以及三种class member function: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;
};
这个class Point在机器中将被如何表现呢?我们如何模塑(modeling)出各种data member和function member呢?
C++对象模型(The C++ Object Model)
Nonstatic data member被置于每一个class object之内,static data member则被存放在所有的class object之外。Static和nonstatic function members也被存放在所有的class object之外,virtual functions则两个步骤支持:
- 每一个class产生出一堆指向virtual functions的指针,放在表格中。这个表格被称为virtual table(vtbl)。
- 每一个class object被添加了指针,指向相关的virtual table。通常这个指针被称为vptr。vptr的设置和重置都由每个class的constructor,destructor和copy assignment运算符自动完成。每个class索关联的type_info object(用来支持RTTI)也是由virtual table指出,通常放在第表格的第一个slot处。
C++对象模型如下图:
这个模型的主要优点在于它的空间和存储效率;主要缺点则是,如果应用程序代码本身未曾改变,但所用到的class objects的nonstatic data members有所修改(可能增加、移除或修改),那么那些应用程序代码同样得重新编译。
加上继承(Adding Inheritance)
C++支持单一继承和多重继承,甚至,继承关系也可以指定为virtual。
在虚拟继承情况下,base class不管在继承串链中被派生多少次,永远只会存在一个实体(称为subobject)。
详细的说明在More Effective C++第24条款中有说明:https://blog.csdn.net/weixin_28712713/article/details/81451023,这本书的后面章节也有讨论。
对象模型如何影响程序(How The Object Model Effiect Programs)
这对程序员带来什么意义呢?不同的对象模型,会导致”现有的程序代码必须修改“以及”必须加入新的程序代码“两个结果。例如下面的函数,其中class X定义了一个copy constructor,一个virtual destructor,和一个virtual function foo:
X foobar()
{
X xx;
X* px = new X;
//foo()是一个virtual function
xx.foo();
px->foo();
delete px;
return xx;
}
这个函数可能在内部被转换为:
//可能的内部转换结果
//虚拟C++码
void foobar(X& _result)
{
//构造_result
//_result用来取代local xx ...
_result.X::X();
//扩展X* px = new X;
px = _new(sizeof(X));
if(px != 0)
px->X::X();
//扩展xx.foo();但不使用virtual机制
//以_result取代xx
foo(&_result);
//使用virtual机制扩展px->foo()
(*px->vptr[2])(px);
//扩展delete px
if(px != 0)
{
(*px->ptr[1])(px); //destructor
_delete(px);
}
//不需要使用named return statement
//不需要摧毁local object xx
return;
}