概述
- 实现多态,C++使用了一种动态绑定的技术,这个技术的核心是“虚函数表”
类的虚函数表
-
每个包含虚函数的类都包含一个虚函数表
-
虚函数表是一个指针数组,其元素是虚函数的指针,每个元素对应一个虚函数的函数指针
-
虚函数表内的元素,即虚函数指针的赋值发生在编译器的编译阶段,虚函数表就可以构造出来了
虚函数表指针
-
虚函数表是属于类的,而不是属于某个具体的对象,一个类只需要一个虚函数表即可,同一个类的所有对象都使用同一个虚函数表
-
对象内部包含一个虚函数表的指针,来指向自己所使用的虚函数表(*_vptr)
-
类的对象在创建时便拥有了这个指针,且这个指针的值会自动被设置为指向类的虚函数表
-
一个类对象只有自身所属虚函数表的指针(而不是继承的类的虚函数表)
动态绑定
class A {
public:
virtual void vfunc1();
virtual void vfunc2();
void func1();
void func2();
private:
int m_data1, m_data2;
};
class B : public A {
public:
virtual void vfunc1();
void func1();
private:
int m_data3;
};
class C: public B {
public:
virtual void vfunc2();
void func2();
private:
int m_data1, m_data4;
};
-
上述代码对应图表
-
子类重写基类的虚函数之后则不再指向基类虚函数,而指向自身实现作用域的虚函数;反之未被重写的虚函数,子类则依旧指向基类作用域的虚函数
-
虚函数表的指针会指向其直接继承的基类的虚函数
int main() { B bObject; A *p = & bObject; // 多态 }
-
B对象在创建时,它的虚函数表指针已经设置为指向B vtbl,声明A的指针来指向对象B,虽然p是基类的指针只能指向基类部分,但是虚函数表指针亦属于基类部分,所以p可以访问到对象b的虚函数表指针
int main() { A aObject; A *p = &aObject; p->vfunc1(); }
- 实际上可以看作
(*(p->__vptr)[n])(p)
- 实际上可以看作
-
执行动态绑定的条件
- 通过指针来调用函数
- 指针upcast向上转型(继承类向基类的转换称为upcast)
- 调用的是虚函数