从内存模型角度来看C++多态实现机制

C++ 中多态的实现原理-虚函数表详解 编译时多态(Compile-time Polymorphism):也称为静态多态性,是在编译时确定的多态性。C++中的函数重载和模板(Templates)是编译时多态的例子。函数重载允许定义多个同名函数,但它们的参数列表不同,编译器根据参数类型或个数来决定调用哪个函数。模板允许编写通用的代码,以适用于不同类型的数据。运行时多态(Run-time Polymorphism):也称为动态多态性,是在运行时确定的多态性。C++中的虚函数和继承是运行时多态的例子。 阅读详情
最近对多态的实现机制比较感兴趣,本文从C++内存模型角度去看待多态的实现机制。实例如下:

#include<iostream>
#include <string>
#include <stdio.h>
using namespace std;

class Animal
{
    public:
           Animal(int a = 1, int b = 2)
           {
               this->a = a;
               this->b = b;
           }

          virtual   void sleep(int minutes = 30)
            {
                cout<<"animal sleep "<<minutes<<" minutes"<<endl;
            }
          virtual  void breathe()
          {
              cout<<"animal breathe"<<endl;
          }
          virtual void eat()
          {
              cout<<"animal eat"<<endl;
          }
          private:
            int a;
            int b;
};


class Fish:public Animal
{
  public:

        Fish(int c) {
             this->c = c;
        }

         virtual void breathe()
            {
                cout<<"fish breathe"<<endl;
            }

         virtual void sleep(int minutes = 50)
            {
                cout<<"fish sleep "<<minutes<<" minutes"<<endl;
            }
          virtual void swim(void) //Fish子类特有函数
          {
              cout<<"fish swim"<<endl;
          }
            private:
            int c;
};



int main()
{
 typedef void (*Fun1)(void); //指向breathe()函数
 Fun1 pFun1 = NULL;
 typedef void (*Fun2)(int); //指向sleep()函数
 Fun2 pFun2 = NULL;

 cout<<"<<<<<<Animal 对象打印信息>>>>>>"<<endl;
 Animal an(1,2);
cout<<"Animal类虚函数表地址:"<<(int*)*(int*)&an<<endl;
 cout<<"对象an内存模型中成员变量a =  "<<* ((int*)&an+1)<<endl;
 cout<<"对象an内存模型中成员变量b =  "<<* ((int*)&an+2)<<endl;
pFun1 =  (Fun1)*(int*)*(int*)&an;
 pFun1();
pFun2 =  (Fun2)*((int*)*(int*)&an+1);
pFun2(50);
pFun1 =  (Fun1)*((int*)*(int*)&an+2);
pFun1();
cout<<"<<<<<<Fish 对象打印信息>>>>>>"<<endl;
 Fish fh(5);

 cout<<"Fish类虚函数表地址:" <<(int*)*(int*)&fh<<endl;
 cout<<"对象fh内存模型中成员变量a =  "<<* ((int*)&fh+1)<<endl;
 cout<<"对象fh内存模型中成员变量b =  "<<* ((int*)&fh+2)<<endl;
 cout<<"对象fh内存模型中成员变量c =  "<<* ((int*)&fh+3)<<endl;
pFun1 =  (Fun1)*(int*)*(int*)&fh;
 pFun1();
pFun2 =  (Fun2)*((int*)*(int*)&fh+1);
pFun2(50);
pFun1 =  (Fun1)*((int*)*(int*)&fh+2);
 pFun1();
pFun1 =  (Fun1)*((int*)*(int*)&fh+3);
 pFun1();
cout<<"<<<<<<Animal指针指向Fish 对象打印信息>>>>>>"<<endl;
Animal *anPtr = &fh;

cout<<"Animal类指针指向Fish类虚函数表地址:" << (int*)*(int*)anPtr<<endl;
 cout<<"Animal类指针指向Fish类所属内存区域a = "<<* ((int*)anPtr+1)<<endl;
 cout<<"Animal类指针指向Fish类所属内存区域b = "<<* ((int*)anPtr+2)<<endl;
pFun1 =  (Fun1)*(int*)*(int*)anPtr;
 pFun1();
pFun2 =  (Fun2)*((int*)*(int*)anPtr+1);
pFun2(50);
pFun1 =  (Fun1)*((int*)*(int*)anPtr+2);
 pFun1();
 pFun1 =  (Fun1)*((int*)*(int*)anPtr+3);
 pFun1();
 return 0;
}

<<<<<<Animal 对象打印信息>>>>>>
Animal类虚函数表地址:0x8049178
对象an内存模型中成员变量a =  1
对象an内存模型中成员变量b =  2

animal sleep 134514480 minutes
animal breathe
animal eat

<<<<<<Fish 对象打印信息>>>>>>
Fish类虚函数表地址:0x8049160
对象fh内存模型中成员变量a =  1
对象fh内存模型中成员变量b =  2
对象fh内存模型中成员变量c =  5

fish sleep 134514480 minutes
fish breathe
animal eat
fish swim

<<<<<<Animal指针指向Fish 对象打印信息>>>>>>
Animal类指针指向Fish类虚函数表地址:0x8049160
Animal类指针指向Fish类所属内存区域a = 1
Animal类指针指向Fish类所属内存区域b = 2

fish sleep 134514480 minutes
fish breathe
animal eat
fish swim


由此可以得到,Animal类an对象与Fish类fh对象的内存布局如下:
 

如果一个类声明了虚函数,编译器就会在其声明的对象中的开始部分增加一个指向虚函数表指针vfptr。此实例中 Animal* anPtr 声明了一个指向Animal对象的指针,当Animal没有声明虚函数时,anPtr所指向的内容并不包括vfptr,当用Fish对象给它赋值时,只将 Fish中的Animal对象复制给anPtr所指向的Animal对象。因此anPtr->breathe()会调用Animal中的breathe()函数。

如果Animal中的breathe()是虚函数,那么当Animal *anPtr = &fh(或者Animal *anPtr = new Fish(5);)执行时,就会把Fish对象的vfptr 和Fish 对象中包含的Animal对象一同复制给anPtr所指向的对象。此后,anPtr所指向的vfptr 是Fish对象的vfptr,因此再调用anPtr->breathe()时,就会调用Fish类中的breathe()函数。

总结:对于虚函数调用来说,每一个对象内部都有一个虚表指针,该虚表指针被初始化为本类的虚表。在程序中,不管你的对象类型如何转换,该对象内部的虚表指针都是固定的,所以,才能实现动态的对象函数调用,这就是C++多态性实现的原理。此外,我们还可以看到,对于访问限定符仅仅作用在编译器层面上的,编译器制定了私有的成员变量不能被继承规则,然而在父类和子类的内存模型中可以看到,子类是在父类已有的内存模型空间中增加子类自有的成员变量。

其特点为:

1. 每一个类都有虚表。

2. 虚表可以继承,如果子类没有重写虚函数,那么子类虚表中仍然会有该函数的地址,只不过这个地址指向的是基类的虚函数实现。如果重写了相应的虚函数,那么虚表中的地址就会改变,指向自身的虚函数实现。

3. 派生类的虚表中虚函数地址的排列顺序和基类的虚表中虚函数地址排列顺序相同。

《深度探索c++内存模型》读书笔记 (一) 第一章 关于对象前言加上封装后的布局成本c++对象模式加上继承C++中的多态对象所占用的内存大小指针的类型加上多态之后 前言 在C语言里面,数据和函数是分开的,它们之间的关联是通过参数和返回值来取得联系。如: typedef struct point3d { float x; float y; float z; } Point3d; void print_point3d(const Point3d *p) { printf("%g %g %g", p->x, p 阅读详情

相关推荐

CTF 命令执行绕过总结

tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示。或:rce-xor-or.php & rce-xor-or.py。# ls -t >shell 将输出输入到shell文件中。异或:rce-xor.php & rce-xor.py。%09(url传递)(cat%09flag.php)sh /flag 2>%261 //报错出文件内容。2、1使用空变量$*和$@,$x,${x}绕过。7、异或无符号(过滤0-9a-zA-Z)more:一页一页的显示档案内容。

jnszstmei的博客 1959

C++对象模型、多态以及单一继承下的运行内存分析

引言 对中高级程序员来说,C++内存模型是C++知识点里比较重要的一部分,对此了解之后便可对C++类的实现机制以及多态性有更多的理解,尤其是C++运行过程中各个对象在内存里的分布情况,以下对这些知识点做简要介绍。 C++类的构成: C++的类由两部分构成,类里的数据和类里的函数,类数据有两种,静态的非静态的,类函数有三种,静态的非静态的,virtual的 对象模型 不同的对象模型会造成布...

Asher_zheng的专栏 584

STM32G0定时器中断实战:HAL库配置TIM2实现精准1秒LED闪烁(附完整代码)

本文深入解析了STM32G0系列微控制器中定时器中断的配置与应用,重点介绍了如何使用HAL库配置TIM2实现精准的1秒LED闪烁。通过详细讲解时钟树分析、预分频系数与自动重装载寄存器的计算原理,并结合CubeMX图形化配置与完整代码示例,帮助开发者从底层理解定时器工作机制,掌握可复用的工程化配置方法。

weixin_29194817的博客 253

图解剖析C++多态与内存模型

导引 看完了Lippman《深度探索C++对象模型》这本书以后,对于多态和虚函数的理解还是比较模糊,直到查阅了不少资料与博文以后,才有恍然大悟的感觉。 在对C++多态进行总结之前,推荐几篇优秀的经典博文: 陈皓的 C++ 对象的内存布局 这篇虽然代码有些小瑕疵,但是瑕不掩瑜 C++ 之 多态 这篇博文代码对理解虚函数表很有帮助。可以拿来自己测试。 C++对象的内存布局以及虚函数表和虚基表 这篇总...

Xiaoqing的博客 1060

异步fifo的UVM验证(最终最终版)

更新了refmdl以及scb

qq_44674008的博客 2988

MuJoCo 入门教程(一)

在 MuJoCo 仿真中输入自定义数字有三种方法。首先,可在 XML 中定义全局数字字段。它们有一个名称和一个实数值数组。其次,可以通过特定元素的自定义数组来扩展某些模型元素的定义。具体方法是在 XML 元素大小中设置 nuser_XXX 属性。第三,数组 mjData.userdata 不用于任何 MuJoCo 计算。用户可以在这里存储自定义计算的结果;请记住,所有随时间变化的内容都应存储在 mjData 中,而不是 mjModel 中。自定义文本字段可以保存在模型中。

机器人控制与仿真应用 1万+

C/C++的内存模型

一、 内存模型的概念         内存模型是C/C++数据抽象的基础,是C/C++最底层的语言设施。不过,C与C++关于内存模型的表述方式是不同的。C++明确提出了内存模型的概念,但C没有这样做,而是对内存模型的构件例如bit和byte单独定义。尽管形式不同,但两者关于内存模型的语义是基本相同的,都由bit构成byte,bit是构成对象的最小单位,而可寻址的最小数据存储单位是byte,这

darthlotus的博客 581

Vue - 详细实现低代码平台,支持拖曳式可视化生成应用软件功能,用户通过拖拽元素、搭积木的方式创建应用(适合迭代的基础架构、低代码平台)

Vue低代码平台-拖曳式拖拉拽可视化生成应用软件,拖拽式低代码数据可视化开发平台,vue实现拖拽,拖拽式Vue组件代码生成平台,基于vue的可视化拖拽代码生成工具,Vue实现可拖拽组件的方法,一个低代码平台的前端部分,靠拖拉拽生成页面。Vue技术栈从零实现低代码可视化搭建平台示例,低代码轮子,通过拖拽就可生成Vue代码的平台来了,vue低代码平台开发相关比低代码更强大的零代码开发平台,这款低代码SAAS数据可视化工具,拖拽生成大屏。vue实现拖拽效果,Vue自由拖拽缩放组件,自定义组件(文本、图片

🏆 前端领域优质创作者 1万+

C++类对象的内存模型

一、关于对象: OOP : OOP的核心思想是多态性。 多态性的含义是“多种形式”,我们把具有继承关系的多个类型称为多态类型,因为我们使用这些类型的多种形式,而无须在意他们的差异。 “基类指针 + virtual虚函数” 实现了C++的多态性。 当我们使用基类指针或引用 调用 基类中定义的一个函数时,我们并不知道该函数真正作用的对象是什么类型,直到运行时才能决定执行哪个版本。 面向对象的三要素:封装,继承,多态。缺一不可。 (单有 封装 的叫 “基于对象”。) C++对象模型: 当一个类中含有虚函数时,编

ArtAndLife的博客 1080

XRoboToolkit —— 基于 PICO 4 Ultra 的机器人遥操作方案(一)

视觉-语言-动作模型(Vision-Language-Action models)的快速发展催生了对大规模、高质量机器人演示数据集的迫切需求。尽管遥操作是数据采集的主要方法,但现有方法存在可扩展性有限、设置流程复杂以及数据质量不佳等问题。本文提出XRoboToolkit,这是一个基于OpenXR标准的跨平台扩展现实(XR)机器人遥操作框架。该系统具备低延迟立体视觉反馈、基于优化的逆运动学算法,并支持多种跟踪模态,包括头部、控制器、手部及辅助运动追踪器。

2506_90492529的博客 3311

innovus:如何在init design之后新增参考库(lib/lef)

如题,在PR过程中经常会遇到这种问题,时序无法收敛,需要新增一套lvt或者hpc的库,怎么办?

m0_61544122的博客 5010

C++对象内存模型

一、虚函数表指针和虚函数表 虚函数表指针个数与派生类继承父类个数有关,多一个父类,派生类就多一个虚函数表指针和虚函数表; 派生类和父类同时含有虚函数时,派生类的虚函数按照父类声明的顺序(从左到右),存放在第一个父类的虚函数表后面; 成员变量按照先声明、先存储、先父类、再子类的顺序存放; 无论是派生类还是父类,当出现虚函数(普通虚函数、纯虚函数、虚虚构函数),虚函数表指针放在内存的最前面; 二、覆盖和继承 派生类和父类出现同名成员变量时,派生类仅仅时将父类的同名承运隐藏了,而非覆盖替换; ...

xiaofeilongyu的博客 467

【Unity】RPG2D龙城纷争(十九)流程与UI界面(终章)

本章为RPG2D系列的终章,在之前的章节中我们已经完成了游戏的所有基本功能,那么用流程与UI界面将其串联起来才是我们整个游戏原型完善的标志。

神码编程 917

从内存模型的角度来看C++多态实现机制和C++析构函数为什么要用虚函数

一、从内存模型角度来看C++多态实现机制 [cpp] view plain copy #include   #include    #include    using namespace std;      class Animal   {       public:              Animal(int a = 1, in

William Zhao's notes 513

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

C++多态的实现及原理详细解析

C++多态的实现及原理详细解析

码城的博客 1万+

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

c++多态实现的机制

1 什么是多态? 多态性可以简单的概括为“1个接口,多种方法”,在程序运行的过程中才决定调用的机制 程序实现上是这样,通过父类指针调用子类的函数,可以让父类指针有多种形态。 2 实现机制 举一个例子: #include class animal { public: void sleep() { cout } void breathe() { cout } };

zyq0335的专栏 4万+

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

C++——多态性实现机制

C++的多态性实现机制剖析1. 多态性和虚函数#include <iostream.h> class animal { public: void sleep() { cout<<"animal sleep"<<endl; } void breathe() { cout<<"animal breathe"<<endl;

Fortune favors the dream of attention. 53万+

C++多态实现机制剖析

面向对象的三大概念:封装,继承,多态。 封装突破了c语言函数的概念;继承实现了代码的复用,那么多态实现了什么价值呢,简单理解就是前人写的代码(框架)可以调用后人写的代码。 1 什么是多态? 多态性可以简单的概括为“1个接口,多种方法”,在程序运行的过程中才决定调用的机制 程序实现上是这样:通过父类指针调用子类的函数,可以让父类指针有多种形态。 2. 理解多态成立的三个条件 对比思考间接赋值成立的三个条件:1. 定义两个变量,2.建立变量之间的联系,3.*p通过地址间接赋值。 多态的单个条件:1.要有继承。2

tbl1234567的博客 287

C++中多态的实现机制

转自(http://blog.youkuaiyun.com/zyq0335/article/details/7657465) 1 什么是多态? 多态性可以简单的概括为“1个接口,多种方法”,在程序运行的过程中才决定调用的机制 程序实现上是这样,通过父类指针调用子类的函数,可以让父类指针有多种形态。 2 实现机制 举一个例子: #include class animal { public

不积跬步无以成千里 427

C++中多态实现机制

http://hi.baidu.com/zhangcy8511/blog/item/d554b2c2d41ac129e5dd3bfd.html 多态是一种不同的对象以单独的方式作用于相同消息的能力,这个概念是从自然语言中引进的。例如,动词“关闭”应用到不同的事务上其意思是不同的。关门,关闭银行账号或关闭一个程序的窗口都是不同的行为;其实际的意义取决于该动作所作用的对象。 大多数面向

梦想照旧实现 1892

【C++入门笔记】多态的实现原理

本文引用自https://blog.youkuaiyun.com/tujiaw/article/details/6753498#,其原文章图片已不可查看。在此基础上扩充了FishC大佬的一些内容。 什么是多态 顾名思义就是同一个事物在不同场景下的多种形态。  此前《【C++入门笔记】覆盖方法和重载方法》已经讲述了函数重载的方法。静态多态是编译器在编译期间完成的,编译器会根据实参类型来选择调用合适的函...

Jeloys的博客 256

(转)c++多态实现的机制

原文地址:http://blog.youkuaiyun.com/zyq0335/article/details/7657465 1 什么是多态?多态性可以简单的概括为“1个接口,多种方法”,在程序运行的过程中才决定调用的机制程序实现上是这样,通过父类指针调用子类的函数,可以让父类指针有多种形态。2 实现机制举一个例子:#include <iostream.h>class animal{...

dianchixian5277的博客 102

C++之多态

多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态 ,例如:买车票,有人买的是全票,而有的人是学生票。

flyingcloud6的博客 885

C++的多态性实现机制剖析

1、多态性和虚函数 我们先看一个例子:   [cpp] view plaincopy #include&lt;iostream.h&gt;   class animal   {   public:       void sleep()       {           cout&lt;&lt;"animal sleep"&lt;&lt;endl;...

iteye_8601的博客 124
上一篇: 电脑的脉搏—时钟频率的来龙去脉
下一篇: cppcheck 单元测试框架浅析
CodingGeek
博客等级 码龄18年 15粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值