首页 > 编程语言 >关于C++ 多态实现技术的深度解析(vfptr,vftable)

关于C++ 多态实现技术的深度解析(vfptr,vftable)

时间:2023-02-11 17:23:13浏览次数:51  
标签:void vfptr 多态 virtual C++ 基类 public

PS:要转载请注明出处,本人版权所有。

PS: 这个只是基于《我自己》的理解,

如果和你的原则及想法相冲突,请谅解,勿喷。

前置说明

  本文作为本人csdn blog的主站的备份。(BlogID=059)
  本文发布于 2018-04-04 17:05:21,现用MarkDown+图床做备份更新。blog原图已丢失,使用csdn所存的图进行更新。(BlogID=059)

环境说明

  无

前言


  关于C++的多态,我就不多说了,我理解的一句话就是:一个接口,多种实现(简称:一对多)。在C++里面,多态的最重要的实现方法为继承,简单来说:就是基类提供接口,子类可以实现基类的接口,不同的子类就构成了基类接口的不同的实现。以上就是C++课本上或者C++原理上的常见的知识。

  而今天这里所说明的是多态是怎么实现的,以及实现的详细方法。我个人认为:只有了解了这些东西后,我们才不会在多态中迷失自己的方向,导致代码稀烂。





c++ 多态




多态的实现

  多态的实现是通过一个指针数组实现的。此指针数组的一般声明如下:

//虚函数表
void ** vfptr;//此ptr指向一个void * 的数组

  说明: vfptr 变量的声明是C++编译器根据:当一个带有虚函数的类定义了一个实例时,编译器会自动在此类的前4bytes(32bit 系统)添加vfptr变量来实现多态。同时编译器会生成一个void *数组来存放实际接口方法地址(其实这里就已经实现了多态,也就是说:这里就已经定义好了这个实例可以调用哪些实际接口方法,例如是来至于基类还是子类等等),也就是虚函数表(vftable),此表是放在生成的可执行文件的数据段。

  总结:这里有一些基本的习惯。

  • vfptr放在一个类的起始相关地址。
  • vftable中的方法按照继承顺序、接口声明顺序赋值。

  以上都是自己瞎扯的原理,看不懂也没有啥问题,毕竟我的语文水平不高,语言组织能力不行,直接跳过查看下面的实例分析。



多态的实现原理解析实例
class Base
{
public:
	Base() {}
	~Base() {}
	virtual void base1(void) = 0;
	virtual void base2(void) {};
	virtual void base3(void) {};
	int base_a = 0;
private:

};
class Base1
{
public:
	Base1() {}
	~Base1() {}
	virtual void base2(void) {};
	virtual void base3(void) {};
	int base_a = 0;
private:

};

class Derive:public Base
{
public:
	Derive() {}
	~Derive() {}
	virtual void base1(void) {}
	virtual void base2(void) {}
	int derive_a = 1;
private:

};
class Derive1 :public Base
{
public:
	Derive1() {}
	~Derive1() {}
	virtual void base1(void) {}
	virtual void base2(void) {}
	virtual void derive1(void) {}
	virtual void derive2(void) {}
	int derive_a = 2;
private:

};

class Derive2:public Derive1
{
public:
	Derive2() {}
	~Derive2() {}
	virtual void derive1(void) {}

private:

};

int main()
{
	Base1 b1;
	Derive d1;
	Derive1 dd1;
	Derive2 ddd1;
    return 0;
}




20200306 动态绑定的补充

关于派生对象地址赋值给基类指针 并使用基类指针调用派生类函数。源码如下:

rep_img

(20200326补充END)

  以下是vs2015的调试分析截图:(若只想了解一下vfptr和vftable是个什么样子,只看此图并结合代码分析足以)

rep_img

友情提示:此图中关于ddd1的vfptr和我们想要的结果是不同的,原因和调试器相关,具体关于ddd1哪里有问题,若有需求,请看以下分析。



多态的实现原理解析实例(进阶版)

  同上一份代码,我们深入到汇编里面,就可以发现一些我们不知道的细节,关于这些汇编中的其他内容部分,若想了解,参考此文章:https://blog.csdn.net/u011728480/article/details/79092194。

  这里我们只分析变量ddd1的生成过程。

  用ida载入我们生成的exe文件。找到main函数中ddd1初始化入口如下:

rep_img


20200306 动态绑定的补充

关于派生对象地址赋值给基类指针 并使用基类指针调用派生类函数。反汇编如下:

rep_img

ddd1对象的vfptr如下:

rep_img

可以发现动态绑定的时候,基类指针的vfptr已经指向了ddd1对象的vfptr。
(20200326补充END)

  这里我们跳转到call后面的地址查看Derive2的构造函数,先调用Derive1的构造函数,再给vfptr赋值。下图是构造函数汇编

rep_img

  下图是vfptr的赋值内容,也就是vftable是什么样子的

rep_img

  这里可以看到,其实此实例调用的是哪些方法(也就实现了多态),早已经在编译时就确定了,只是这里才赋值而已,所以可以说是动态绑定或者静态绑定。

  下图为Derive1构造函数以及vftable值:

rep_img
rep_img

  下图为Base构造函数以及vftable的值:

rep_img
rep_img

  以上总结:我们可以发现vfptr经过了多次赋值的,不同的时间段,vfptr值不一样,所以在构造实例的时候,不同时段调用同一个接口,会有不同的方法。

同时也可以得出一个结论,每个接口的实现类都有一个虚函数表,包括接口类本身,这些虚函数表在编译时就确定了,只是vfptr赋值的时候,是在程序运行时确定的。

  根据以上的分析,可以解决许多我们关于多态的疑问。





后记


  无

参考文献




打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)
qrc_img

PS: 请尊重原创,不喜勿喷。

PS: 要转载请注明出处,本人版权所有。

PS: 有问题请留言,看到后我会第一时间回复。

标签:void,vfptr,多态,virtual,C++,基类,public
From: https://www.cnblogs.com/Iflyinsky/p/17112140.html

相关文章

  • GCC&&G++ C && C++ 内嵌汇编和调用汇编函数的方法(x86,ARM自己对照改)
    PS:要转载请注明出处,本人版权所有。PS:这个只是基于《我自己》的理解,如果和你的原则及想法相冲突,请谅解,勿喷。前置说明  本文作为本人csdnblog的主站的备份。(BlogID......
  • 多态实现让电脑去读写各种移动设备的数据
    多态实现让电脑去读写各种移动设备的数据usingSystem;namespace电脑_移动硬盘_U盘_MP3{classProgram{staticvoidMain(string[]args)......
  • c++登录注册功能实现代码
    //ConsoleApplication26.cpp:此文件包含"main"函数。程序执行将在此处开始并结束。////#define_CRT_SECURE_NO_WARNINGS#define_CRT_NONSTDC_NO_DEPRECATE#includ......
  • C++ 地球人口承载力
    题目描述假设地球上的新生资源按恒定速度增长。照此测算,地球上现有资源加上新生资源可供xx亿人生活aa年,或供yy亿人生活bb年。为了能够实现可持续发展,避免资源枯......
  • c++ 调用第三orm框架matador的方法通过vs2019
    1.安装matador编译好window版安装包,在安装目录下复制include和lib文件夹到自己的项目目录一下2.自己的mfc目录如图所示,粘贴制include和lib文件夹 3.用vs2019打开自己......
  • 『 再看.NET7』让json序列化体现多态
    从System.Text.Json诞生,就在努力增加功能和提升性能,在.NET7中,又带来了多态的适配。下面是一个父类Customer,两个子类,WechatCustomer和LineCustomer。publicclas......
  • 『 再看.NET7』让json序列化体现多态
    从System.Text.Json诞生,就在努力增加功能和提升性能,在.NET7中,又带来了多态的适配。下面是一个父类Customer,两个子类,WechatCustomer和LineCustomer。publicclas......
  • 『 再看.NET7』让json序列化体现多态
    从System.Text.Json诞生,就在努力增加功能和提升性能,在.NET7中,又带来了多态的适配。下面是一个父类Customer,两个子类,WechatCustomer和LineCustomer。publicclassCu......
  • C++语言程序设计课程设计任务书[2023-02-11]
    C++语言程序设计课程设计任务书[2023-02-11]C++语言程序设计课程设计任务书一.课程设计的目的全面系统的学习面向对象程序设计的基本概念、基本语法和编程方法。正确......
  • C++PrimerPlus中文第六版第10章编程练习答案
    1、//bankaccount.h#ifndefBANKACCOUNT_H_#defineBANKACCOUNT_H_#include<string>classBankAccount{private: std::stringm_account_name; constchar*m_......