浅谈动态多态实现原理"/>
浅谈动态多态实现原理
简介:
如果一个类中声明有虚函数,大多数编译器就会为这个类创建一个虚函数表(virtual function table)简称虚表(vtab)。
虚表中存放了该类中所有虚函数的地址,虚表属于整个类,不属于某个具体的对象,该类所有对象共享虚表。
当实例化该类对象时,会自动把该类虚表的首地址(简称为 虚指针 vptr)存在该对象中,当使用基类指针/基类引用 调用该虚函数时,大概的过程为:
基类指针/基类引用 -》具体对象 -》虚指针 -》 虚函数表 -》 具体虚函数地址 -》调用虚函数
大概图示如下:
验证代码:
#include <iostream>using namespace std;class Parent {public:virtual void func1() {cout << "Parent::func1()" << endl;}virtual void func2() {cout << "Parent::func2()" << endl;}private:int a;virtual void func3() {cout << "Parent::func3()" << endl;}
};class Child : public Parent{public:/* 重写func2函数 */void func2() {cout << "Child::func2()" << endl;}private:int b;
};int main() {Child c;Parent *p;p = &c; /* 取基类对象的地址 */Child *pc = &c;/* 因为64位环境下指针大小为8,所以将其转换为long型的方便解引用 */long *pl = reinterpret_cast<long *>(pc);/* 将long型的地址转换为long*的指针 */long *vptr = reinterpret_cast<long *>(*pl);/* 定义一个函数指针PF */using PF = void (*)();/* 提取虚函数表中第一个元素 */PF pf1 = reinterpret_cast<PF>(vptr[0]);pf1();/* 提取虚函数表中第二个元素 */PF pf2 = reinterpret_cast<PF>(vptr[1]);pf2();/* 提取虚函数表中第三个元素 */PF pf3 = reinterpret_cast<PF>(vptr[2]);pf3();cout << "===================" << endl;/* 通过基类的指针调用 */p->func1();p->func2();return 0;
}
运行结果:
总结:
如果一个类中声明有虚函数,大多数编译器就会为这个类创建一个虚函数表,虚表中存放了该类中所有虚函数的地址,虚表属于整个类,不属于某个具体的对象,该类所有对象共享虚表。在子类中如果没有重写虚函数,会继承父类的虚函数,重写则会覆盖父类的虚函数。
彩蛋:
再验证过程中在父类中定义了一个私有的虚函数,但是在类外依旧能通过虚表地址调用它,从另一方面可以看出类的公有和私有权限只在编译阶段会判断。
更多推荐
浅谈动态多态实现原理
发布评论