虚表和虚表指针 详解

 

 Hi~!欢迎来到碧波空间,平时喜欢用博客记录学习的点滴,欢迎大家前来指正,欢迎欢迎~~
✨✨ 主页:碧波
📚 📚 专栏:C++ 系列文章

📚 虚表(Virtual Table)和虚表指针(vptr)是C++中实现多态性的重要机制。它们通过动态绑定(或运行时多态性)实现了在基类指针或引用下调用派生类的虚函数。

目录

虚函数(Virtual Function)

虚函数表(Virtual Table,VTABLE)

虚表指针(vptr)

虚表和虚表指针工作原理


虚函数(Virtual Function)

虚函数是在基类中声明为 virtual 的成员函数。在派生类中可以根据需要进行重写(override)。它允许在运行时动态地确定调用哪个版本的函数,这是实现多态性的一种关键机制。

虚函数表(Virtual Table,VTABLE)

虚表是每个包含虚函数的类的静态成员之一,它存储了类的虚函数的地址。每个类有一个对应的虚表,其中的每个条目是一个指向相应虚函数的指针。当类被定义时,编译器会在其虚表中生成对应的虚函数条目。

虚表指针(vptr)

 虚表指针是一个隐藏的指针,存在于每个包含虚函数的类的对象中。它指向该类的虚函数表(虚表)。当调用一个虚函数时,实际上是通过对象的虚表指针找到对应的虚表,然后根据函数的偏移量来调用正确的函数。

虚表和虚表指针工作原理

🎯 通过示意图来更好地理解虚表和虚表指针的概念,有 Base 类和 Derived 类:

Base 类对象内存布局:
+--------------+
|  vptr (Base) | --> 指向 Base 类的虚表
+--------------+
|  Base 类的数据 |
+--------------+

Derived 类对象内存布局:
+----------------+
|  vptr (Derived) | --> 指向 Derived 类的虚表
+----------------+
|  Derived 类的数据 |
+----------------+

每个对象的开头都有一个虚表指针。这个指针指向其对应的类的虚表。例如,Base 类对象的虚表指针指向 Base 类的虚表,而 Derived 类对象的虚表指针则指向 Derived 类的虚表。

🎯 通过简单的示例代码,演示如何利用虚表和虚表指针实现动态多态性;

class Base {
public:
    virtual void func1() {
        std::cout << "Base::func1()" << std::endl;
    }
    virtual void func2() {
        std::cout << "Base::func2()" << std::endl;
    }
};

class Derived : public Base {
public:
    void func1() override {
        std::cout << "Derived::func1()" << std::endl;
    }
};


int main() {
    Base* basePtr;
    Derived derivedObj;

    basePtr = &derivedObj;

    // 虚函数的调用
    basePtr->func1();  // 输出 "Derived::func1()"
    basePtr->func2();  // 输出 "Base::func2()"

    return 0;
}

当编译器在编译的时候会分别为类Base和类Derived 创建属于各自类的虚函数表。并Derived 当创建父类指针指向对象的时候,会初始化vptr指针,指向该对象所属类的虚函数表。

通过指向子类对象的父类指针,调用成员函数时,会先判断是否为virtual 虚函数,如果是虚函数的话,会通过vptr访问对应的类虚函数表中所存放的成员函数指针。依次实现多态。

🎯 结合示例,总结工作过程。

虚函数声明与重写:

在基类中,如果一个函数被声明为虚函数(使用 virtual 关键字),它可以被派生类重写。

虚表的构建:

每个类的虚函数表在编译时构建。虚表中的每个条目存储了对应虚函数的地址,这些地址是相对于类的基址的偏移量。

虚表指针的初始化与使用:

当创建一个对象时,如果该对象所属的类有虚函数,编译器会在对象的内存布局中插入一个虚表指针。这个指针被初始化为指向该类的虚表的地址。

动态绑定:

当调用一个虚函数时,实际被调用的函数取决于对象的实际类型(而不是引用或指针的静态类型)。这是因为编译器会通过对象的虚表指针来查找对应的虚表,然后根据虚函数的偏移量来调用正确的函数实现。

🔥 虚表和虚表指针区别:

虚表属于类,虚表指针属于对象。

虚函数表:在编译阶段生成,编译器将类中 虚函数的地址存放在虚函数表中,虚函数
表存在于全局数据区.data,每个类仅有一个,供所有对象共享。
虚表指针:指向虚函数表首地址的一个指针,存在于每个基类对象的内存中,在调用构
造函数构造对象时,设置虚表指针__vfptr

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

碧 波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值