C++虚函数

本文详细介绍了C++中虚函数的工作原理,包括虚函数表的构造和虚函数调用过程。每个含有虚函数的类都会有一个虚函数表,其中存储着函数指针。当通过基类指针调用虚函数时,编译器根据虚函数表在运行时确定实际调用的函数。对于多重继承的情况,可能存在多个虚函数表,调用过程会涉及更多的查找和替换。文章还讨论了虚函数在多继承情况下的处理方式。
摘要由CSDN通过智能技术生成

C++中虚函数的实现及基本原理

定义

简单来说,那些被virtual 关键字修饰的函数就是虚函数。
而每一个含有虚函数(无论是其本身的,还是继承来的)的类都至少有一个与之对应的虚函数表,其中存放着该类所有的虚函数所对应的函数指针。例:
在这里插入图片描述
其中:

  • B的虚函数表中存放B::foo 和 B::bar 两个函数指针。
  • D的虚函数表中既存放着继承自B 的虚函数指针B::foo,也存放着重写(override)了基类B 的虚函数B::bar 的D::bar, 还有D类新增的虚函数D::quz。

虚函数表的构造过程

从编译器的角度来说,B的虚函数表很好构造,D的虚函数表构造过程相对复杂。下面给出了构造D的虚函数表的一种方式(仅供参考):
在这里插入图片描述
提示:该过程是由编译器完成的,因此也可以说:虚函数替换过程发生在编译时。

虚函数调用过程

以下面的程序为例:
在这里插入图片描述
编译器只知道pb是B*类型的指针,并不知道它指向的具体对象类型 :pb可能指向的是B的对象,也可能指向的是D的对象。

但对于“pb->bar()”,编译时能够确定的是:此处operator->的另一个参数是B::bar(因为pb是B*类型的,编译器认为bar是B::bar),而B::bar和D::bar在各自虚函数表中的偏移位置是相等的。

无论pb指向哪种类型的对象,只要能够确定被调函数在虚函数中的偏移值,待运行时,能够确定具体类型,并能找到相应vptr了,就能找出真正应该调用的函数。

B::bar是一个虚函数指针, 它的ptr部分内容为9,它在B的虚函数表中的偏移值为8(8+1=9)。

当程序执行到“pb->bar()”时,已经能够判断pb指向的具体类型了:

如果pb指向B的对象,可以获取到B对象的vptr,加上偏移值8((char*)vptr + 8),可以找到B::bar。
如果pb指向D的对象,可以获取到D对象的vptr,加上偏移值8((char*)vptr + 8) ,可以找到D::bar。
如果pb指向其它类型对象…同理…

多重继承

当一个类继承多个类,且多个基类都有虚函数时,子类对象中将包含多个虚函数表的指针(即多个vptr),例:
在这里插入图片描述
其中:D自身的虚函数与B基类共用了同一个虚函数表,因此也称B为D的主基类(primary base class)。

虚函数替换过程与前面描述类似,只是多了一个虚函数表,多了一次拷贝和替换的过程。

虚函数的调用过程,与前面描述基本类似,区别在于基类指针指向的位置可能不是派生类对象的起始位置,以如下面的程序为例:
在这里插入图片描述
转载自:虚函数的实现的基本原理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值