【C++】深入理解虚表

本文深入解析虚表概念及其内存结构,展示如何通过虚表调用虚函数,并探讨虚函数在继承与覆盖情况下的表现。

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

简述虚表

虚表是记录本类中所有虚函数地址的一个表格。

虚表的内存结构

如下,我们设计了一个类,存在两个虚函数。

class A
{
public:
	virtual void fun1() {
		cout << "a" << endl;
	}

	virtual void fun2() {
		cout << "b" << endl;
	}
};

通过A实例化a,再看看a的内存结构。_vfptr就是虚表!!!可以把它看成存放了void*型对象的数组。 而_vfptr的两个成员分别代表fun1函数的指针和fun2函数的指针。这也正好验证了虚表就是记录本类中所有虚函数地址的一个表格。
在这里插入图片描述

获取虚表

经测试,通过如下代码可以获取虚表。

A a;
int *vptr = (int *)(*(int*)(&a));

再看内存监视信息,我们发现vptr的地址和_vfptr的地址一样,测试通过-v-
在这里插入图片描述

通过虚表调用虚函数

看上图,我们发现vptr[0]的值与虚表中第一个成员的值相等。那我么可以通过吧vptr[0]转换成fun1函数类型,来达到不可告人的目的。

typedef void (*Fun)(void);
Fun f1 = (Fun)vptr[0];
f1();

调用后,控制台打印“a”,象征着我们尝试成功。同理,我们也可以通过vptr[1]来调用fun2函数。

虚表中虚函数的排列顺序

通过上图,我们很容易就可以看出,是按函数的声明顺序排列的。虽然简单,但还是请记住了。不要一不小心调用了虚析构函数,程序直接崩溃。

继承中覆盖虚函数

我们再设计一个AA类,继承A,并且在A中实现fun1()函数。

class AA : public A
{
public:
	virtual void fun1() {
		cout << "aa" << endl;
	}
};

通过AA实例化aa,再看看aa的内存结构。
在这里插入图片描述
发现没有,AA::fun1。我们只实现了fun1(),虚表中的fun1函数使用的是AA类中的实现,而fun2函数使用的时A类中的实现。有没有隐隐约约嗅到动态绑定的味道?

结语

看完本篇文章,是不是对神秘莫测的虚表有了更一步的认识。
这里只是从内存层面讲解了虚表,欲了解更加透彻,请查阅“继承”,“动态绑定”等知识。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值