22(1).虚函数表(多态的原理)

虚函数表

即多态的原理

  • 覆盖和隐藏只是表象,实际是通过虚函数表来实现的(联想到虚基类的继承中的虚基表)
//查看虚函数的内容
class Base
{
public:
	Base()
	{
		base_data = 10;
	}
public:
	virtual void fun()
	{
		cout<<"This is Base::fun()"<<endl;
	}
	virtual void show()
	{
		cout<<"This is Base;;show()"<<endl;
	}
	void fun1()
	{
		cout<<"This is Base::fun1()"<<endl;
	}
private:
	int base_data;
};

class D : public Base
{
public:
	D()
	{
		d_data = 8;
	}
public:
	void fun()
	{
		cout<<"This is D::fun()"<<endl;
	}
	void show()
	{
		cout<<"This is D::show()"<<endl;
	}
	virtual void print()
	{
		cout<<"This is D::print()"<<endl;
	}

private:
	int d_data;
};

typedef void(*vfptr_type)();  //将函数指针类型重命名为vfptr_type

void PrintVTable(vfptr_type vtable[])  
{
	cout<<"虚表地址:>"<<vtable<<endl;
	//由于虚函数表存放的函数指针个数不知道,但是虚函数表的最后一个函数指针的结尾后面是nullptr,由此便可访问到虚函数表中所有的函数指针
	for(int i=0; vtable[i]!=nullptr; ++i)
	{
		vtable[i](); //(vtable+1)();  //虚函数表中的函数指针解引用
	}
}
void main()
{
	//Base b;
	D d;
	
	cout << sizeof(d) << endl;
	vfptr_type *vtable = (vfptr_type*)(*(int*)&d); 
	//由于 创建的派生类对象从起始位置开始存放的分别时vfptr(32bit系统下是4bit,64bit系统下是8bit),基类数据成员,派生类数据成员
	//所以将派生类对象的地址强转成int*类型就相当于拿到了vfptr,由于虚函数表是不占类的空间只是同一个虚函数表指针指向,所以对其解引用就拿到了虚函数表的首元素地址
	//通过之前的强制类型转换指针无法正确偏移函数指针类型大小,所以再强转回去
	PrintVTable(vtable);
}


重写的原理是,基类和派生类的虚函数都会存放在虚函数表中,只不过构成重载的派生类函数地址会覆盖掉基类的函数地址,所以构成了覆盖的假象
覆盖(重写)的原理

隐藏的原理是
???
VS下虚函数表是存在代码段的

  • 一般继承(无虚函数覆盖)

基类和派生类的虚函数按照其声明顺序放于虚函数表中 父类的虚函数在子类的虚函数前面

一般继承(有虚函数覆盖)

虚函数表中派生类中与基类中三同的虚函数,派生类的虚函数指针会覆盖掉基类的虚函数指针

多重继承(无虚函数覆盖)

每个基类都有一个虚函数表指针指向一个虚函数表,每个基类指向的虚函数表存放自己基类的虚函数
派生类的虚函数按声明顺序存放在第一个(按继承顺序的第一个)基类所指向的虚函数表的后面,并且父类的虚函数在子类的虚函数前面

多重继承(有虚函数覆盖)

每个基类都有一个虚函数表指针指向一个虚函数表,每个基类指向的虚函数表存放自己基类的虚函数
派生类的虚函数按声明顺序存放在第一个(按继承顺序的第一个)基类所指向的虚函数表的后面,与基类虚函数三同的会覆盖基类的虚函数地址,并且父类的虚函数在子类的虚函数前面

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值