C++深度探索虚函数指针示例

 更新时间:2022年12月19日 12:37:50   作者:Huuaaaaa  
虚函数主要通过V-Table虚函数表来实现,该表主要包含一个类的虚函数的地址表,可解决继承、覆盖的问题,下面这篇文章主要给大家介绍了如何通过一篇文章带你掌握C++虚函数的来龙去脉,需要的朋友可以参考下

代码描述:定义一个Person类为基类,ChinesePer 类与EnglishPer类都继承于此基类。

class Person
{
public:
	void speak() {
		cout << "说人话" << endl;
	}
private:
	int m_type = 1 ;
};
class ChinesePer :public Person {
public:
	void speak() {
		cout << "说中国话chinese..." << endl;
	}
};
class EnglishPer :public Person {
public:
	void speak() {
		cout << "说英国话english..." << endl;
	}
};

先看看此时各个类占用的内存信息:

int main() {
	int person_size = sizeof(Person);
	int Chineseper_size = sizeof(ChinesePer);
	int Englishper = sizeof(EnglishPer);
}

可以看到三个类的大小都为4个字节,占用的情况就是 类中的m_type变量。

将基类中的 speak() 函数加上virtual关键字 ,成为虚函数后再次查看内存字节大小:

可以看到多出了4个字节大小的空间(X86),三个类的大小都为 8。其实就是多出了一个指针的大小,4个字节 ,创建一个子类对象就可以明显看出来:

可以得出结论一:继承过来的成员变量 m_type(4个字节) + _vfptr(4个字节) = 8个字节。

继续探索虚函数表的原理, 创建以下子类对象并通过父类指针指向子类对象调用speak函数发生多态:

int main(){
	ChinesePer chs;
	ChinesePer chs2;
	EnglishPer eng;
    Person *ptr = &chs;		//父类指针指向子类对象
	Person *ptr1 = &chs2;
	Person *ptr2 = &eng;
	ptr->speak();
	ptr1->speak();
	ptr2->speak();
}

以上代码执行后会发生多态:

此时我们看看三个对象的内存分布:

用图片简要描述一下就是:

在这里可以先得到结论二: 同一个子类的所有对象共享一个虚函数表,指向虚函数表的指针_vptr是相同的。

在内存分布上查看一下 eng对象的虚函数指针地址情况:

可以看到该虚函数指针的地址上的值,存放的正是 该子类中的重写函数 speak()函数的地址。

如果把这个地址的值,修改为 Chineseper 类中的重写函数speak() 的地址值,会发生什么?

手动修改了eng对象中虚函数指针内的地址值,将改值本来是存放的是 EnglishPer 类中的speak() 函数的地址,现在更改为 ChinesePer 类中speak() 函数的地址。

单步走发生多态:

至此可以得出结论三:

当基类函数加了virtual 关键字后,虚函数的调用方法是间接调用:先查虚函数表的地址(也就是指向虚函数表的指针 _vptr),再查虚函数表中的虚函数指针。

不妨在基类继续添加两个虚函数

class Person
{
public:
	virtual void speak() {
		cout << "说人话" << endl;
	}
	virtual void eat() {
		cout << "吃饭" << endl;
	}
	virtual void sleep() {
		cout << "睡觉" << endl;
	}
private:
	int m_type =1 ;
};

子类只重写了speak函数,查看一下chs对象的虚函数指针地址存放的值:

的确存放的还是各个函数的地址,且是连续存放的,因此在进行查表调用虚函数的时候,也是每移动4个字节指向的就是一个函数的指针地址。

可以简要描述一下形式就很直观了:

总结:

1.增加了virtual 关键字的对象头部4个字节是一个指针,指向了虚函数表的地址(单继承情况下)。

2.同一个子类的所有对象共享一个虚函数表,指向虚函数表的指针_vptr是相同的。

3.当基类函数加了virtual 关键字后,虚函数的调用方法是间接调用:先查虚函数表的地址(也就是指向虚函数表的指针 _vptr),再查虚函数表中的虚函数指针。

到此这篇关于C++深度探索虚函数指针示例的文章就介绍到这了,更多相关C++虚函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++ deque容器的用法详解

    C++ deque容器的用法详解

    在处理一些数组的事情,所以随手保留一下Deque容器的使用方法很有必要,接下来通过本文给大家重点介绍C++ deque容器的用法及deque和vector的区别讲解,感兴趣的朋友跟随小编一起看看吧
    2021-05-05
  • C语言实现电子英汉词典系统

    C语言实现电子英汉词典系统

    这篇文章主要为大家详细介绍了C语言实现电子英汉词典系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • Linux下C语言修改进程名称的方法

    Linux下C语言修改进程名称的方法

    这篇文章主要介绍了Linux下C语言修改进程名称的方法,涉及Linux下使用C语言操作进程的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • c语言描述回文数的三种算法

    c语言描述回文数的三种算法

    这篇文章主要介绍了c语言描述回文数的三种算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • 浅析C语言中的setjmp与longjmp函数

    浅析C语言中的setjmp与longjmp函数

    以下是对C语言中的setjmp与longjmp函数进行了详细的介绍,需要的朋友可以过来参考下
    2013-09-09
  • C++中malloc与free、new与delete的详解与应用

    C++中malloc与free、new与delete的详解与应用

    今天小编就为大家分享一篇关于C++中malloc与free、new与delete的详解与应用,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • Visual Studio2000系列版本安装OpenGL的图文教程

    Visual Studio2000系列版本安装OpenGL的图文教程

    这篇文章主要介绍了Visual Studio2000系列版本安装OpenGL的图文教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • C++读入XML文件示例

    C++读入XML文件示例

    本篇文章主要介绍了C++读入XML文件,读取和设置xml配置文件是最常用的操作,TinyXML是一个开源的解析XML的C++解析库,感兴趣的小伙伴们可以参考一下。
    2016-12-12
  • C++实现日期计算器详细代码示例

    C++实现日期计算器详细代码示例

    这篇文章主要给大家介绍了关于C++实现日期计算器的相关资料,基于C++编写的简单的日期计算器,供大家参考,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-03-03
  • C++实现将数据写入Excel工作表的示例代码

    C++实现将数据写入Excel工作表的示例代码

    直观的界面、出色的计算功能和图表工具,使Excel成为最流行的个人计算机数据处理软件。在本文中,您将学习如何使用 Spire.XLS for C++ 创建 Excel 文档,以及如何将数据写入 Excel 工作表
    2023-03-03

最新评论