虚函数表分析

虚函数表分析

结合上一次探究的代码,我们可以得到父类对象和子类对象内存布局示意图

image-20220326145811233

对于上图的总结

  • 包含虚函数的类才会有虚函数表,同属于一个类的对象共享这个虚函数表,但是各个对象都有各自的vptr(虚函数表指针),但是该指针所指向的地址相同(虚函数表首地址)

  • 父类中有虚函数子类中也会有虚函数,即父类中有虚函数表子类中也会有虚函数表,即便子类并没有覆盖父类的任何虚函数

    class Derive : public Base {
    public:
    	// 空    
    };
    
    sizeof(Derive) = 4 // 说明子类中有虚函数表指针
    

    但是,对于此类情况,无论父类还是子类,都只会各自拥有一个虚函数表,不能认为子类继承了一个父类的虚函数表并且拥有一个自己的虚函数表。(但是多重继承情况下,子类可以拥有多个虚函数表)

  • 如果子类中完全没有新的虚函数,则可以认为子类的虚函数表和父类的虚函数表内容相同,但这两个表在内存中是处于不同的位置的

  • 虚函数表中的每一项保存着一个虚函数的地址,但如果子类的虚函数表某项和父类中的虚函数表某项代表同一个函数,则该表项所指向的该函数的地址应该相同

  • 超出虚函数表部分的内存内容不可测

继续探索

#include <iostream>
using namespace std;

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; }
};

int main()
{
	typedef void(*Func)(void); // 定义了一个函数指针,typedef就代表Func是一个函数指针类型,可以将它当作类型使用
	
	Derive derive;
	long* pvptrderive = (long*)(&derive);
	long* vptrderive = (long*)(*pvptrderive); // 虚函数表的地址

	Derive derive2 = derive; // 复制构造
	long* pvptrderive2 = (long*)(&derive2);
	long* vptrderive2 = (long*)(*pvptrderive2);

	// 父类指针指向子类
	Base base = derive; // 直接用子类对象给父类对象值
	long* pvptrbase = (long*)(&base);
	long* vptrbase = (long*)(*pvptrbase);

	printf("vptrderive:x0: %p\n", vptrderive);	// 00E19B6C
	printf("vptrbase:x0:   %p\n", vptrderive2); // 00E19B6C 
	printf("vptrderive2:x0:%p\n", vptrbase);	// 00E19B34
	

	return 0;
}
vptrderive:x0: 00E19B6C
vptrbase:x0:   00E19B6C
vptrderive2:x0:00E19B34
  • base
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值