虚函数探秘

C++的多态分为动态多态和静态多态,其中静态多态主要靠重载和模板来实现,而动态多态则主要靠继承来实现了。

那么静态和动态,怎么算静,怎么算动呢?静态多指编译期能决定的事情,而动态多指运行时才决定的事情。例如重载,在编译期生成符号的时候就已经确定不同的函数了,而继承的重写(override)则是在运行到具体的代码位置确认指针内部的虚函数表指向的函数地址时才知道执行哪个函数,被称为动态多态。

虚函数表指针

虚函数表指针指向虚函数表,虚函数表每个类一个,如果是单继承的话子类和父类的虚函数表会合体,下面是一个简单的例子

class Father {
public:virtual void fatherfunction() {cout << "fatherfunction" << endl;}
};class Child : public Father {
public:virtual void childfunction() {cout << "childfunction" << endl;}
};Child c;
Father f;

用过调试器查看变量内部可以看到Child类的对象c中有父类的虚函数表指针,但是自己的呢?单纯一个父类对象也有自己的虚函数表指针,为什么Child类的对象自己的虚表指针不见了呢?
20190820161700.png

那么一个猜测就是子类的虚函数表和父类的虚函数表合体了,这个猜测到底正不正确呢?得想个办法验证一下!

一般虚表指针存放在对象地址空间的头4位,这里先取得上图中看到的Father的vptr指向的虚表,虚表地址的获取需要获取虚表指针中存放的值。

 cout << hex << "virtual table address: " << *(int *)(&c) << endl;

然后是获得fatherfunction函数指针的地址

cout << hex << "fatherfunction address: " << (int *)*(int *)(&c) << endl;
typedef void(*FUN)();Child c;
cout << hex << "virtual table address: " << *(int *)(&c) << endl;
cout << hex << "fatherfunction address: " << (int *)*(int *)(&c) << endl;FUN father_func = (FUN)*((int *)*(int *)(&c));FUN child_func = (FUN)*((int *)*(int *)(&c) + 1);father_func();
child_func();

得到的结果如下图所示

20190820172707.png

虚函数表中存放的紧接着father_func函数地址的下一个就是child_func的地址,因此是合并了。

PS:简单解释一下取函数指针的代码
20190820173918.png
续表为手误,是虚表。图不好改就不改了

静态函数不能是虚函数

静态成员不属于任何对象,所以就算加上了virtual也没有意义
静态函数没有this指针,虚函数表存在于对象的地址空间,使用对象的this指针访问,但是静态函数没有this指针故也无法访问虚函数表。

静态函数不能是const也不能是volatile

const成员函数要求使用者为const类对象,再换一个说法就是要求this指针为const,但是静态函数没有this指针,故使用const关键字修饰静态函数毫无意义

PS:volatile是一个关键字用来表示当前语句不会被编译器优化,且要求每次直接读值

多继承的时候虚表指针表现

多继承时,对象内部会有多个虚表指针指向多个虚函数表,如果自己也能继续继承,那么自己的续表会和第一个虚表合体,虚表合体这个在上面已经描述过了,多个多继承的话也会合并,是会和内存空间的第一个虚表合并。

class Father {
public:virtual void fatherfunction() {cout << "fatherfunction" << endl;}
};class Mother {
public:virtual void motherfunction() {cout << "motherfunction" << endl;}
};class Child : public Father, public Mother {
public:virtual void childfunction() {cout << "childfunction" << endl;}
};

把类的继承关系改成这样,让Child类继承自Father和Mother,此时Child的对象c中有几个虚表指针?

20190820173051.png

答案是两个分别是两个类的虚表指针,此时为了判断合体,还是用上面提到的方法,也能成功,发现子类的虚表是存在头4个字节的虚表指针所指向的虚表内的。

而这个虚表指针的先后顺序和声明继承的顺序一致,public Mother如果在public Father之前的话就会变成如下图所示
20190820173303.png

转载于:https://www.cnblogs.com/lenomirei/p/11384480.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/349636.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Errai框架简介

Errai是Red Hat开发和维护的框架&#xff0c;旨在结合GWT和JEE世界的优点。 根据Red Hat的说法&#xff0c;Errai是基于GWT的框架&#xff0c;用于使用下一代Web技术构建富Web应用程序。 在此简单声明的背后&#xff0c;存在一种与GWT完全不同的开发方式&#xff0c;在下面的文…

动态壁纸安卓_高清无水印!这4款壁纸软件,让你的手机好看又独特

手机与我们每日相伴&#xff0c;我们总会精心挑选各种图片设置为手机壁纸&#xff0c;有时换个壁纸就像换了一种心情一样。但网上搜索的壁纸大同小异&#xff0c;有没有风格独特又有趣的&#xff1f;今天就给大家推荐4款各具特色的壁纸App&#xff0c;保证给你耳目一新的感觉。…

在线生成安卓APP图标

移动应用图标/启动图生成工具&#xff0c;一键生成所有尺寸的应用图标/启动图 在线生成安卓APP图标生成 图标在 线 在线图标 安卓图标 生成图标 https://icon.wuruihong.com/ 在线png图片压缩 png压缩 https://compresspng.com/zh/ 在线gif图片压缩 gif压缩 https://www.soog…

NOIP模拟测试29「爬山·学数数·七十和十七」

爬山题解不想写了 学数数 离散化然后找到以每一个值为最大值的连续子段有多少个,然后开个桶维护 那么怎么找以每一个值为最大值的连续子段个数 方法1(我的极笨的方法) 考试时我的丑陋思路, 定义极左值为左面第一个大于当前值的值,极右值为右面第一个大于当前值的值 ,找到最大值…

手机音频拼接软件_良心分享:业界最顶尖的软件!

01短视频的爆火&#xff0c;让全民都接触了“剪辑”要知道在最最最开始大众离它很远&#xff0c;更多是一种职业而非爱好最具影响力的是抖音、B站等平台抖音让更多人接触到了剪辑哔哩让更多人学会剪辑技术虽然抖音的视频时长普遍较短但这并不妨碍剪辑技术的展现比如&#xff0c…

java堆内存和堆外内存_Java堆空间,本机堆和内存问题

java堆内存和堆外内存最近&#xff0c;我正在和一个朋友讨论为什么Java进程使用的内存比启动Java进程时设置的最大堆多。 代码创建的所有Java对象都是在Java堆空间内创建的&#xff0c;其大小由-Xmx选项定义。 但是一个Java进程由很多空间组成&#xff0c;而不仅仅是Java堆空间…

springboot实践1

环境安装 安装jdk 推荐安装jkd1.8,我使用的是mac&#xff0c;假设已经安装好homebrew,则jdk的安装指令是&#xff1a; brew install java 在 ~/zshrc ,添加两行 export JAVA_HOME你的jdkPath export PATH$PATH:$JAVA_HOME;然后保存&#xff1b; 输入 echo ${JAVA_HOME} 回车&…

电脑入门基础教程_ARM入门最好的文章------转载一位资身工程师的入门心得

开始学ARM一团雾水,不知道如何入手.这个介绍的比较全面.本人认为aRM入门最好的文章1. 抓住51开发ARM这几个月来我一直都爬在51的问题&#xff0c;自己都有一点笑自己了&#xff0c;用了4个月的时间&#xff0c;来巩固51的原理和程序&#xff0c;还好我自己算是走过来了&#xf…

项目包装组织

程序包是Java的基本概念&#xff0c;是您开始用该语言编程时偶然发现的第一件事。 作为一个初学者&#xff0c;您可能不太在意软件包的结构&#xff0c;但是随着您成为经验丰富且成熟的软件开发人员&#xff0c;您开始思考可以采取哪些措施来提高其效率。 有几个主要选项需要考…

NOIP模拟测试30「return·one·magic」

magic 题解 首先原式指数肯定会爆$long$ $long$ 首先根据欧拉定理我们可以将原式换成$N^{\sum\limits_{i1}^{i<N} [gcd(i,N)1] C_{G}^{i} \%phi(p)}\%p$ 根据欧拉函数是积性的得出$phi(54184622)phi(2)*phi(27092311)$ 然后$phi(27092311)27092310$ $phi(2)1$所以$phi(541…

python作用域的理解-理解Python的UnboundLocalError(Python的作用域)

今天写代码碰到一个百思不得解为什么会出错的代码&#xff0c;简化如下&#xff1a; 1 2 3 4 5 6 7 x10 deffunc(): ifsomething_true(): x20 print(x) func() 意图很明显&#xff0c;首先我定义了一个全局的x&#xff0c;在函数中&#xff0c;如果有特殊需要&#xff0c;就重新…

threadlocals_如何使用ThreadLocals射击自己

threadlocals它将很好地启动。 像大多数故事一样。 您会发现一个新概念&#xff0c;并对其功能感到惊讶。 然后突然装备了这把新锤子&#xff0c;一切开始看起来像钉子。 根据我们过去几个月的经验&#xff0c; java.lang.ThreadLocal真是一锤定音。 我想这全都归结为ThreadLo…

ASP.NET Core Web API

1.简单介绍 ASP.NET Core Web API 是 ASP.NET Core MVC 的一个功能。ASP.NET Core MVC 包含了对 Web API 的支持。可以构建多种客户端的 HTTP 服务。ASP.NET Core Web API可用于在 .NET Core 上构建 RESTful 应用程序。 框架包含对 HTTP 内容协商的支持&#xff0c;内置支持以 …

win8配置_《FIFA 20》PC配置公布 最低仅需i3+GTX660

EA公布了新作《FIFA 20》的PC配置需求&#xff0c;玩家最低仅需 i3-2100 GTX 660 显卡即可进行游戏&#xff0c;推荐配置则为 i3-6300T GTX 670 显卡&#xff0c;考虑到本作的逼真画面效果&#xff0c;这配置可以说是非常亲民&#xff0c;另外硬盘空间需要大约 50 GB。最低配…

Thymeleaf + Spring中的验证

总览 我们将要讨论的重要主题涉及空值&#xff0c;空字符串和输入验证&#xff0c;因此我们不会在数据库中输入无效数据。 在处理空值时&#xff0c;我们使用了Java 1.8中引入的java.util.Optional 。 0 – Spring Boot Thymeleaf示例表单验证应用程序 我们正在为一所大学构…

技术管理规划-设定团队的职能

背景 职责 团队是干什么的 初步自查团队 1.公司为什么给我团队&#xff1f;希望我产出什么&#xff1f;完成对除了c端健康领域探索的研发任务&#xff0c;产出技术类产品 2.团队存在的独特价值是什么&#xff1f;研发过lx健康这款基础app,研发能力强&#xff0c;熟悉硬件相关技…

开发转测试没人要_前端开发,测试,后端,该如何选择?

一般来说前端会比后端简单一些的&#xff0c;初学者或者转行可能考虑前端多一点&#xff0c;但是后端开发的薪水又比前端高一些&#xff0c;就是比较枯燥。前端开发我目前一直在自学前端&#xff0c;从网上找资料&#xff0c;然后听课&#xff0c;只要是对编程有兴趣&#xff0…

技术管理规划-如何设定团队的目标

团队管理规划有4个互相关联的要素&#xff1a; 职能目标团队路径在未来的3个月&#xff0c;6个月&#xff0c;1年&#xff0c;2年&#xff0c;3年&#xff0c;5年中&#xff0c;你希望带着你的团队抵达一个什么样的目的地&#xff0c;也就是团队的目标。 更加清楚目标意味着什么…

a8处理器相当于骁龙几_天玑820相当于骁龙什么处理器?天梯图秒懂联发科天玑820性能排名...

5月18日&#xff0c;联发科发布了全新 天玑820处理器&#xff0c;号称目前最强中端芯&#xff0c;受到不少网友关注。联发科近年来在手机CPU市场沉寂多年&#xff0c;今年异常给力&#xff0c;先后发布了天玑1000/L、天玑800等多款处理器&#xff0c;采用了全新的命名方式&…

hibernate 继承_Hibernate继承:每个类层次结构的表

hibernate 继承在本教程中&#xff0c;我们将了解如何在hibernate中实现继承。可以通过3种方式在hibernate中实现继承。在本文中&#xff0c;我们将看到其中一种&#xff0c;即每个类层次结构一个表。 Hibernate中的继承&#xff1a; Java是面向对象的语言&#xff0c;继承是J…