虚函数对象布局模型
这里关键实现思想就是把一个在类里定义的一集虚函数定义为一个指向函树的指针数组。这样,对虚函数的调用就简单变成通过数组一个间接函树调用。对每个有虚函数的类都存在一个这样的数组。一般称为虚函数表或者VTBL.。这些类的每个对象都包含一个隐式指针,一般称为vprt,指向该类的虚函数表。
//例如:
class A{
int a;
public:
virtual void f();
virtual void g(int);
virtual void h(double);
};
class B:public A{
public:
int b;
void g(int); //override A::g()
virtual void m(B *);
};
class C:public B{
public:
int c;
void h(double); //orerride A::h()
virtual void n(C*);
};
对类C的一个对象看起来大概是这样:
vtbl 如下表 :
&A::f |
---|
&B::g |
---|
&C::h |
---|
&B::m |
---|
&C::n |
---|
|
对虚函数的函数调用被编译系统编译成一个间接调用。例如:
void f(C* p)
{
p->g(2);
}
将变成某种类似下面的东西:
(*(p->vptl[1]))(p,2); 这并不是唯一可能实现的方式,优点是简单和运行的高效,问题是如果更改了一个类的虚函数集合,所有使用他的代码都必须重新编译。
覆盖和虚函树匹配
虚函数只能被派生类里的函树覆盖,该函数具有相同的函树名,参数,和返回类型。
class Base{
public:
virtual void f();
virtual void g(int);
};
class Derived: publci Base{
public:
void f(); //override Base::f()
void g(char); //doesn't override Base::g()
};