虚函数和虚表vtable详解--每日一题

本文深入探讨了C++中虚函数的工作原理,包括虚函数表的构建与动态绑定过程,以及单继承和多继承场景下虚函数重写的机制。通过具体代码示例,解释了虚函数如何实现多态性,并讨论了虚表指针vptr的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目
原文:
How do virtual functions work in C++?
译文:
C++中的虚函数是如何工作的?

分析
虚函数是在调用时动态绑定的,这就依赖于虚函数表进行工作。
如果在一个基类中,有函数被关键词virtual进行修饰, 那么一个虚函数表就会被自动构建起来去保存这个类中虚函数的地址。同时编译器会为这个类的所有对象添加一个隐藏指针vptr指向虚函数表。
如果在派生类中没有重写虚函数, 那么派生类中虚表存储的是父类虚函数的地址;相反地,如果在派生类中重写父类的虚函数,派生类的虚表中将覆盖父类在该虚函数的地址。
每当虚函数被调用时, 虚表会决定具体去调用哪个函数。因此,C++中的动态绑定是通过虚函数表机制进行的。当我们用基类指针指向派生类时,虚表指针vptr指向派生类的虚函数表。 这个机制可以保证派生类中的虚函数被调用到。

例子
1,例子一–单继承

class Base {
public:
    virtual void f() {cout<<"base::f"<<endl;}
    virtual void g() {cout<<"base::g"<<endl;}
    virtual void h() {cout<<"base::h"<<endl;}
};

class Derive : public Base{
public:
    void g() {cout<<"derive::g"<<endl;}
};

此时基类Base的虚表是:
在这里插入图片描述
而派生类Derive的虚表是:
在这里插入图片描述
2,例子二–多继承
在这里插入图片描述
可以看出,多继承中派生类的虚函数重写,会导致所有继承的基函数对应虚表中的地址被覆盖,而派生类新加的函数g1()则只出现在vtable中一次。

补充
腾讯的一道关于虚表的面试题–
问题:
“有一个类指针,指向类实例化的对象,在程序的运行过程中,这个类指针指向的对象崩溃了,这个类指针的虚函数表被破坏了,如何定位这个问题?”
解答:
类的虚函数表被破坏是不可能的,因为这个 vtable 是放在只读数据区rodata。修改 vtable 会导致 segment fault段错误(数组越界、内存泄漏、空指针等错误会引起这个报错),这样检查 coredump(包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息等的一个文件) 文件就知道哪里造成的vtable修改。
类的虚表指针是可能被修改的,比如说访问虚表的指针出现错误越界,或者误成为空指针、悬挂指针等等。

最后我们来看一下虚函数使用中的所有内存分配情况:
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值