浅谈动态多态实现原理

简介:  

        如果一个类中声明有虚函数,大多数编译器就会为这个类创建一个虚函数表(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;
}

运行结果:

总结:

如果一个类中声明有虚函数,大多数编译器就会为这个类创建一个虚函数表,虚表中存放了该类中所有虚函数的地址,虚表属于整个类,不属于某个具体的对象,该类所有对象共享虚表。在子类中如果没有重写虚函数,会继承父类的虚函数,重写则会覆盖父类的虚函数。

彩蛋:

再验证过程中在父类中定义了一个私有的虚函数,但是在类外依旧能通过虚表地址调用它,从另一方面可以看出类的公有和私有权限只在编译阶段会判断。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值