虚函数+多态实现原理(一个冷门知识)

文章探讨了C++中的多态实现,主要涉及虚函数的定义和重写规则。通过类的继承和虚函数,基类指针可以调用子类的重写函数。文章解释了这是因为对象含有虚函数表(vfptr),在实例化对象时,子类会拥有独立的虚表,调用函数是根据虚表中的地址进行。多态实际上是在调用时动态绑定,保持函数接口不变,但实现可变。
摘要由CSDN通过智能技术生成

目录

多态实现

虚函数定义

先说原理

抛出问题

探究多态底层

冷门知识


多形态的大海

多态实现

完成类多态体现,多态两个条件:
虚函数重写
父类指针或者引用去调用虚函数。

虚函数定义

虚函数重写/覆盖条件 : 函数 + 三同 (函数名、参数、返回值)
不符合重写,就是隐藏关系
特例1: 子类虚函数不加virtual,依旧构成重写(实际最好加上)

特例2:重写的协变。返回值可以不同,要求必须时交子关系的的指针或者引用(极易报错)

为什么呢?明明是father类引用呀。

先说原理

因为对象虚函数表的不同,基类的引用/指针其实指向的是子类的虚表,就好像基类函数给覆盖重写一样。

抛出问题

先写俩类。

class father
{
public:
	virtual void func1() 
	{
		printf("father printf\n");
	}
	virtual void no_vir()
	{}

protected:
	const char* _father_val = "fathar";
};

class son : public father
{
public:
	virtual void func1()
	{
		printf("son printf\n");

	}
protected:
	const char* _son_val = "son";
};

 这究竟是什么原因呢????

探究多态底层

进入调试模式查看father实例化对象parent里有啥。 

_father_val我们知道是成员变量,这_vfptr是什么?

他是一个数组指针指向一个指针数组。这数组保存的是函数地址。这奇奇怪怪的什么情况看看parent的大小

这个二级指针属于这对象中。

看看child对象有什么。

自己_son_vals数据+ 父类继承虚表与父类_father_val.让我们对比一下,parent与child的虚表

 首先vfptr虚表的地址不一样,说明了我们的child与parent对象的虚表是相互独立的,看看各自指向的数组,发现[1]保存的地址数据相同,而[0]的地址数据保存的不同。好关键的来啦

 

将parent对象与child对象都传入test函数。发现调用的函数不同。其实就是应为这的引用与指针调用函数其实是根据虚表的函数地址调用。

画图画图!

 其实所谓的多态其实就是指针或者引用访问的时候派生类中继承基类虚表是,检测自己的函数是否可以重写基类虚函数,可以的话就会改变自己基类中虚表中该函数地址的值,改变为自己函数的地址。


冷门知识

我们的函数替换的时候其实保存的依旧是基类的函数接口。俗话讲:头还在换了个身体。因为在汇编中我们可以知道函数调用call前先需要,将实参压栈(如果写了缺省值就缺省压栈),然后再去调用call函数地址。

运行代码

 重写替换了函数体内代码,但是函数头还是基类的头!!

如果有人这样考你,他一定是一个老六!!

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

云的小站

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

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

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

打赏作者

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

抵扣说明:

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

余额充值