您的位置:首页 > 编程语言 > C语言/C++

读书笔记 《深度探索c++对象模型》 (3)

2010-07-03 04:22 267 查看
第四章:Function语意学
4.2 虚拟成员函数
a) 单一继承下的virtual function
一个class只会有一个virtual table。每一个table内含其对应的class object的所有active virtual functions的函数实体地址。包括:

这个class自己定义的virtual function,它override了一个可能存在的base class virtual function函数实体。
继承自base class的函数实体。
一个纯虚函数实体。

b) 多重继承下的virtual function
在多重继承中实现virtual functions。其复杂度在于第二个以及之后的base class身上。例如:
class Base1 {
public:
Base1();
virtual ~Base1();
virtual void SpeakClearly();
virtual Base1* clone() const;
protected:
float data_Base1;
};

class Base2 {
public:
Base2();
virtual ~Base2();
virtual void mumble();
virtual Base2* clone() const;
protected:
float data_Base2;
};

class Derived : public Base1, public Base2 {
public:
Derived();
virtual ~Derived();
virtual Derived* clone() const;
protected:
float data_Derived;
};
有如上派生关系,如果有:
Base2 *pbase2 = new Derived;
delete pbase2;
那么第一行会将pbase指针调整以指向Base2 subobject。否则的话,类似
pbase2->data_Base2;
这种非多态应用都会失败。而在第三行的时候,由于要调用Derived的析构,所以this指针又会被调整到Derived对象开头。
其实现是运用了一种叫Thunk的技术,在代码里面插了一小段汇编代码,用来做两件事情:调整this指针的位置,跳转到virtual function的位置。
于是,对于多重继承来说,有多少个base class,就有多少个vptr,分别指向多少张virtual table。每个virtual table的内容参见《深度探索c++对象模型》P165页的图。注意,由于base_1和derived class共享一个virtual table,所以该virtual table内的内容最多。甚至包括了Base_2::mumble。不过Base_2::mumble的真正地址存放在Base_2对应的virtual table中。所以想要通过derived class的指针条用mumble方法,需要利用thunk调整this指针,这就是下面三种情况的第2种。(注意,某base class的指针,new出来的对象是derived的,也不能调用其他base class的方法)指针的类型是什么,就使用那个基类相应的virtua table。派生类和第一个base class使用的是同一个virtual table。
有三种情况,第二或者后继的base class会影响到virtual functions的支持。这时候需要利用thunk调整this指针。
// 情况1,通过一个指向第二个base class的指针调用一个derived class virtual function
Base2 *pbase2 = new Derived;
// 调用~Derived(), pbase2 必须向后调整sizeof(Base1)个字节
delete pbase2;

// 情况2,通过一个指向Derived class的指针调用一个继承自第二个base class的virtual function
Derived *pderived = new Derived;
// pderived必须向前调整sizeof(Base1)个字节
pderived->mumble();

// 情况3,先向后调整sizeof(Base1)个字节
Base2 *pbase21 = new Derived;
// 调用clone方法时,pbase21调整到Derived对象开头,于是clone的Derived版本会被调用,它会返回一个Derived的指针,然后再被向后调整到指向Base2 SubObject
Base2 *pbase22 = pbase21->clone();

c) 虚拟继承下的virtual functions
class Point2d {
public:
Point2d();
virtual ~Point2d();
virtual void mumble();
virtual float z();
protected:
float _x, _y;
};

class Point3d : public virtual Point2d {
public:
Point3d();
~Point3d();
float z();
protected:
float _z;
};
由于Point2d和Point3d的起始位置不一样,所以两者之间的转换也需要做this指针调整。所以对于Point3d object来说(编译器是VC),有两张virtual table,一个是继承下来的,里面内容z()和析构函数变成了derived class的z()和析构。mumble()应该保持不变。另一长virtual table里面多了一个virtual base class object的offset,其余一样。(见《深度探索c++对象模型》P169页的图)
不过有些编译器如GCC则是将这个offset加到第一张table中,于是GCC编译器编译的结果也只有一张virtual table。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: