1.1.3 C++对象模型(The C++ Object Model)
C++对象模型的主要优点在于它空间和存取时间的效率;主要缺点是,如果应用程序代码本身并未改变,但所用的class object的nonstatic data members有所修改(可能是增加、移除或修改),那么那些应用程序代码同样得重新编译。关于这点,前面的的表格驱动模型就提供了较大的弹性,因为它多提供了一层间接性,不过它也因此付出空间和执行效率两方面的代价。加上继承 (Adding Inheritance)
C++支持单一继承:class Libarary_materials {...};
class Book : public Library_materials {...};
class Rental_book : public Book {...};
C++也支持多重继承:
class iostream:
public istream,
public ostream {...};
甚至,继承关系也可以指定为虚拟:
class istream : virtual public ios {...}
class ostream : virtual public ios {...}
在虚拟继承的情况下,base class不管在继承串链中被派生多少次,永远只会存在一个实体,例如iostream之中就只有virtual ios base class的一个实体。
在一个derived class如何在本质上模塑base class的实体呢?在"简单对象模型"中,每一个base class可以被derived class object内的一个slot指出,该slot内含base class subobject的地址,这个体制的 主要缺点是,因为间接性而导致空间和存取时间上的额外负担,优点则是class object的大小不会因其base classes的改变而受到影响。
另一种base table模型,这种模型的base class table被产生出来时,表格中的每一个slot内含一个相关的base class地址,这很像virtual table内含每一个virtual function的地址一样,每一个class object内含一个bptr,它会被初始化,指向其base class table.这种策略的 主要缺点是由于间接性而导致的空间和存取时间上的额外负担,优点则是在每一个class object中对于继承都有一致的表现方式:每一个class object都应该在某个固定位置上安放一个base table指针,与base classes的大小或数目无关。第二个优点是,不需要改变class objects本身,就可以放大、缩小、或更改base class table.
不管上述哪一种体制,"间接性"的级数都将因为继承的深度而增加,例如一个Rental_book需要两次间接存取才能够探取到继承自Library_materials的members,而Book只需要一次。如果在derived class内复制一个指针,指向继承串链中的每一个base class,倒是可以获得一个永远不变的存取时间。当然这必须付出代价,因为需要额外的空间来放置额外的指针。
C++最初采用的继承模型并不运用任何间接性:base class subobject的data members被直接放置于derived class object中,这提供了对base class members最紧凑而且最有效率的存取。缺点是base clas members的任何改变,包括增减、移除或改变类型,都使得所有用到此base class或者其derived class的objects必须重新编译。
自C++2.0起才新导入的virtual base class,需要一些间接的base class表现方法。virtual base class的原始模型是在class object中为一个有关联的virtual base class加上一个指针,其他演化出来的模型则若不是导入一个virtual base class table,就是扩充原已存在的virtual table,以便维护每一个virtual base class的位置。
对象模型如何影响程序 (How the Object Model Effects 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->vtbl[2])(px);
// 扩展delete px;
if (px != 0) {
(*px->vtbl[1])(px);
_delete(px);
}
// 不需使用named return statement
// 不需要销毁local object xx
return;
}
没有创建临时变量对象,也不需要销毁临时对象。