【C++】深度探索C++对象模型之虚拟成员函数(virtual member function)


virtual function的一般实现模型:每一个class有一个virtual table,内含class之中有作用的virtual function的地址。然后每个object都有一个vptr,指向virtual table的所在。


为了支持virtual function的机制,必须首先对于多态对象有某种形式的“执行期类型判断法(runtime type resolution)”。


在C++中,多态(polymorphism)表示:以一个public base class的指针(或reference),寻址出一个derived class object。


识别一个class是否支持多态的唯一适当方法,是看看是否含有virtual function。


假如有例子如下:

Point *ptr1, *ptr2;
ptr1 = new Point2D;
ptr2 = new Point3D;
ptr1->z();

 

其中z()是一个virtual function, 为了在执行期调用正确的z(), 需要知道

  • ptr所指对象的真实类型
  • z()实例的位置
所以在实现上,我们需要为每一个多态的class object增加两个members
  • 一个字符串或数字,表示class的类型
  • 一个指针,指向某表格,表格中有程序的virtual function的执行期的地址。
    注意,上述所说的地址在程序执行之后,表格的大小和内容都不会改变。
如何寻址
  • 为了找到表格,每一个class object被安插了一个由编译器内部产生的指针,指向该表格
  • 为了找到函数地址,每一个virtual function被指派一个表格索引值。
每一个class只会有一个virtual table, virtual table的存储内容
每一个table内含其对应的class object中所有active virtual function函数实例的地址, 包括:
  • class所定义的函数实例,overriding可能存在的base class virtual function的函数实例
  • 继承自base class的函数实例。即derived class决定不改写virtual function时才出现的情况
  • pure_virtual_called()函数实例,扮演pure virtual function的空间保卫者角色,也可以当做执行期异常处理函数。
在单一继承中,一般每个上述的active virtual function的实例在virtual table中的布局的slot是一致的。所以对于调用
ptr->z();
以上信息足够使得编译器将调用转化为:
(*ptr->vptr[ 4 ])(ptr);
唯一在执行期才能够知道的东西是:slot 4到底是指向哪个z()的实例。

假设我们有以下的继承关系:
class Derived : public Base1, public Base2;
其中三个类中分别有虚析构函数,成员函数mumble(), 以及对应对象的clone()函数。如Base2
virtual ~Base2();
virtual void mumble();
virtual Base2 *clone() const;
当执行下述语句时:
Base2 *pbase2 = new Derived;
此时新的Derived对象的地址必须调整以指向其Base2 subobject。编译器会产生以下代码:
Derived *temp = new Derived;
Base2 *pbase2 = temp ? temp + sizeof(Base1) : 0;
而当程序删除pbase2所指的对象时,如
delete pbase2;
此时指针将会再次被调整,以指向Derived对象的起始处。上述的offset的加法在编译时期不能直接设定,因此pbase2所指的真正对象只有在执行期才会确定。






参考

深度探索C++对象模型,侯捷,  第四章 Function语意学


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值