首页 > 其他分享 >虚函数以及虚函数表

虚函数以及虚函数表

时间:2024-04-09 19:11:49浏览次数:28  
标签:虚表 函数 以及 对象 派生类 基类 指针

虚函数的作用主要是实现了多态的机制。简单来说,就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这样子就可以让父类的指针有“多种形态”,这是一种泛型技术。就是试图使用不变的代码来实现可变的算法。

每个对象占用存储空间的只是该对象的数据部分,函数代码属于公用部分。

参考博文:https://www.cnblogs.com/zhxmdefj/p/11594459

C++内存分区分为五个部分:

1.栈:由编译器在需要的时候自动分配,不需要时自动清除变量存储区,通常存放局部变量,函数参数等。

2.堆:是由malloc等分配的内存块,和堆十分相似,用free来释放。

3.自由存储区:由new分配的内存块,由程序员释放,如果程序员没有释放掉,资源将由操作系统在程序结束后自动回收。

4.全局/静态存储区:全局变量和静态变量被分配到同一块内存中

5.常量存储区:这是一块特殊存储区,里边存放常量,不允许修改

(堆的自由存储区其实不过是同一块区域,new底层实现代码中调用了malloc,new可以看成是malloc智能化的高级版本)

静态成员函数和非静态成员函数都是在类的定义时放在内存的代码区的,都是属于类,但是类为什么只能直接带哦用静态类成员函数,而非静态类成员函数(即使函数没有参数)只有类对象才能调用呢。

原因是:类的非静态类成员函数其实都包含了一个指向类对象的指针型参数(即this指针),因此只有类对象才能调用(此时this指针有实值)

 

虚函数表

C++通过继承和虚函数来实现多态性,虚函数通过一张虚函数表来实现的,虚函数表解决了继承,覆盖,添加虚函数的问题,保证了其真实反应实际的函数。

原理:

通过为每一个类对象添加一个隐藏成员,隐藏成员保存了一个指针,这个指针叫虚表指针,它指向了一个虚函数表。

虚函数表就像一个数组一样,表中有许多的槽,每个槽中存放的是一个虚函数的地址(也就是数组中存放着指向每个虚函数的指针),因此每个类都使用一个虚函数表,每个类对象用一个虚表指针。

在有虚函数的类的实例化对象中,这个表被分配在了这个实例对象的内存中,用父类的指针来操作一个子类的时候,虚函数表就像一个地图一样,指明了实际应该调用的函数。

例如:

基类对象包含一个虚表指针,指向基类的虚函数表

派生类对象也将包含一个虚表指针,指向派生类虚函数表

1.如果派生类重写了基类的虚方法,该派生类虚函数表将保存重写的虚函数的地址,而不是基类的虚函数的地址

2.如果基类中的虚方法没有在派生类中重写,那么派生类将继承基类中的虚方法,而且派生类中虚函数表将保存

基类中未被重写的虚函数地址,但是如果派生类中定义了心得虚方法,则该虚函数的地址也将被添加到派生类虚函数表中。

 

找到虚函数表

C++的编译器会保证虚函数表的指针存在于对象实例中最前面的位置(为了保证取虚函数表有着最高的性能,在有多层继承

或者是多重继承的情况下),意味着我们通过对象实例的地址得到这种虚函数表的地址,然后就可以遍历其中函数指针,

并调用响应的函数。

 

单继承(无覆盖)

1.虚函数按照其声明顺序放于表中

2.父类的虚函数在子类的虚函数前

 

单继承(有覆盖)

1. 覆盖的函数被放到了虚表中原来父类虚函数的位置

2.没有被覆盖的函数依旧

 

多重继承(无覆盖)

多继承下,虚函数表存储方式发生了变化,C++编译器在对象内加入了一个隐藏成员,现在你可以理解为,在多继承时加入了

多个隐藏成员,也就是说有多个虚函数表。

 

多重继承(有覆盖)

多继承下,虚函数表存储方式会发生变化,并且覆盖的函数被放到了虚表中原来父类虚函数的位置,没有被覆盖的函数依旧,但是有多个虚函数表

 

虚函数表会引发的安全性问题

1.通过父类型的指针访问子类自己的虚函数

2.访问非public的虚函数

 

标签:虚表,函数,以及,对象,派生类,基类,指针
From: https://www.cnblogs.com/huwy-123/p/18124590

相关文章

  • Python函数
    一、函数定义以及作用函数/方法/function(功能):函数是组织好的,可重复使用的,用来实现单一或相关联功能的代码段(块)。函数能提高应用的模块性和代码的重复利用率。比如我们天天使用的函数print(),这个就是函数(一个Python内置的函数)。也可以自己创建函数,这类函数就叫做用户自定义函数......
  • 3.类与对象(中篇)介绍了类的6个默认构造函数,列举了相关案例,实现了一个日期类
    1.类的6个默认成员函数如果一个类中什么成员都没有,简称为空类。空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。默认成员函数是一种特殊成员函数:​......
  • 网络攻防中黑客常用的信息收集手段以及信息泄漏途径,详细方法以及工具介绍
    网络攻防中黑客常用的信息收集手段以及信息泄漏途径,详细方法以及工具介绍。网络攻防中的信息收集是黑客攻击前的重要步骤,其目的是通过各种手段获取目标网络的详细信息,以便为后续的攻击活动提供支持。信息收集的手段多种多样,包括但不限于网络扫描、社会工程学、数据挖掘等。......
  • 网络通讯的流程以及代码
     用于演示socket的客户端:#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<unistd.h>#include<netdb.h>#include<sys/types.h>#include<sys/socket.h>#include<arpa/inet.h>......
  • Springboot 添加License 以及生成证书和证书验证
    1.先准备生成cer证书及私钥,公钥##(1).生成私匙库#validity:私钥的有效期多少天 365 #alias:私钥别称 privateKey#keystore:指定私钥库文件的名称(生成在当前目录) privateKeys.keystore#storepass:指定私钥库的密码(获取keystore信息所需的密码) public_password#key......
  • 关于ros中的回旋函数
    首先spinOnce和spin区别:spin就会进入一个循环体,一直检测消息队列的回调函数,而spinonce则只检测一遍消息队列,然后接着运行下面的语句。首先要了解:ROS中,publisher和subscriber都有一个消息队列用于数据收发时候的缓存。ROS话题的通信是异步的,也就是publisher只管不停的发但......
  • ES查询之聚合函数、分组查询
    目录一、前言二、准备数据三、avg四、max五、min六、sum七、多个聚合和嵌套聚合七、分组查询一、前言聚合函数大家都不陌生,同数据库的聚合函数一样,elasticsearch中也没玩出新花样,所以,这一章相对简单,只需要记得下面几个用法即可:avgmaxminsum聚合的两个主要的......
  • Item30:inline函数
    芝士wa2024.4.9原理内联函数是C++的增强特性之一,用来降低程序的运行时间。作用机理:把内联函数的函数体在编译器预处理的时候替换到函数调用处(副本),这样代码运行到这里的时候就不需要花时间去调用函数(减少了函数调用过程的入栈出栈开销)。此外,内联函数仅仅是对编译器的内联建议......
  • Set集合以及其中实现类的底层原理分析
    Set集合的特点无序:存取顺序不一致如存入张三、李四、王五。而遍历获取到的是李四,张三,王五不重复:可以去除重复无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素set集合的实现类HashSet:无序、不重复、无索引LinkedHashSet:有序、不重复、无索......
  • DISM(Deployment Image Servicing and Management)工具可以用于修复损坏的 Windows 映像
    DISM(DeploymentImageServicingandManagement)工具可以用于修复损坏的Windows映像文件(通常是WIM或VHD文件),以及损坏的系统文件。DISM工具通常用于修复Windows安装映像或运行中的操作系统。您可以使用DISM工具来扫描和修复损坏的系统文件,方法如下:打开命令提示符:......