【C++】多态虚表

news2024/9/22 14:55:47

多态——多种形态

多态的分类:

1.静态多态:函数重载和运算符重载(复用函数名)

2.动态多态:派生类和虚函数实现运行时多态

静态多态和动态多态的区别:

静态多态的函数地址早绑定——编译阶段确定函数地址

动态多态的函数地址晚绑定——运行阶段确定函数地址

另一种分类:

1.重载多态--函数重载&运算符重载

2.包含多态--virtual

3.强制多态--强制类型转换 _cast

4.参数多态--模板


地址早绑定和晚绑定

下面代码中父类:Animal,成员函数:speak,子类:Cat,成员函数:speak;

函数地址早绑定:

先使用父类的构造函数,输出animal speak。

class Animal
{
public:
    void speak(){ cout << "animal speak" << endl; }
};
class Cat :public Animal
{
public:
    void speak() { cout << "cat speak" << endl; }
};
void doSpeak(Animal &animal)
{
    animal.speak();
}
int main1()
{
    Cat cat;
    doSpeak(cat);//animal speak
    //父子之间允许类型转换,函数地址早绑定
    return 0;
}

函数地址晚绑定:

父类中使用虚函数,子类重写speak函数覆盖,输出cat speak。

实现动态多态:

1.有继承关系

2.子类要重写(函数返回值类型、名称、参数列表都相同)父类的虚函数

动态多态的使用:父类的 指针 或者 引用 执行子类对象!!!

子类将父类的虚函数表继承下来,如果子类重写了这个虚函数,则会将之前的虚函数覆盖,但父类自己的没有改变,当父类的指针或引用指向子类对象时,发生多态。

如果是基类同名同参的虚函数,则子类中可以不用写virtual。

class Animal
{
public:
    virtual void speak() { cout << "animal speak" << endl; }//加一个虚的关键字
};
class Cat :public Animal
{
public:
    void speak() { cout << "cat speak" << endl; }
};
void doSpeak(Animal &animal)
{
    animal.speak();
}
int main()
{
    Cat cat;
    doSpeak(cat);//cat speak
    return 0;
}

虚表

类中如果有虚函数,则会有一个(继承来的会有多个)vfptr虚函数指针。

如果是个空类,则大小为1个字节:占位。

在不算继承的情况下,如果里面只有虚函数(无论多少个),则为四个字节,一个指针的大小。指针指向一个虚表,虚表里面放着虚函数的入口地址。

class A
{
public:
    virtual void fa() { cout << "A::fa" << endl; }
    virtual void ga() { cout << "A::ga" << endl; }
    virtual void ha() { cout << "A::ha" << endl; }
private:
    int m_i;
    int m_j;
};
int main()
{
    A a;    
}

且其他成员地址都在虚表之后

可以把这个虚表看作是函数指针数组,可以定义一个函数指针指向这个数组,

int main()
{
    A a;
    typedef void (*Fun)();//函数指针
    Fun pf = NULL;
    pf = (Fun) * ((int*)*(int*)(&a));
    pf(); //A::fa
    pf = (Fun) * ((int*)*(int*)(&a) + 1);
    pf();//A::fb
    pf = (Fun) * ((int*)*(int*)(&a) + 2);
    pf();//A::fc
}

类的地址第一个内容就是这个虚表地址:(int*)(&a),//如果不强转的话&a是a*类型的

fa的地址为虚表第一个元素(解引用):(int*)*(int*)(&a),

最后再解引用就是fa函数:*((int*)*(int*)(&a))

之后转成函数指针类型:(Fun)*((int*)*(int*)(&a))

就可以用函数指针调用虚函数了

虚表的个数

对于多继承,每个父类有自己的虚表。子类将新的虚函数放到第一个父类的虚表中。

下面A有一个虚指针,B有一个虚指针,C有一个虚指针,D继承了ABC的虚指针,并将自己独有的虚函数地址放在继承下来的A的虚表中

class A
{
public:
    virtual void fa() { cout << "A::fa" << endl; }
    virtual void ga() { cout << "A::ga" << endl; }
};
class B
{
public:
    virtual void fb() { cout << "B::fb" << endl; }
    virtual void gb() { cout << "B::gb" << endl; }
};
class C
{
public:
    virtual void fc() { cout << "C::fc" << endl; }
    virtual void gc() { cout << "C::gc" << endl; }
};
class D :public A, public B, public C
{
public:
    virtual void fd() { cout << "D::fd" << endl; }
    virtual void gd() { cout << "D::gd" << endl; }
};
void main()
{
    D d;
    cout << sizeof(D) << endl;//12,继承了三个虚指针,修改了第一个
    typedef void (*Fun)();
    Fun pf = (Fun) * ((int*)(*(int*)(&d)) + 1);
    pf();//A::ga
    pf = (Fun) * ((int*)(*(int*)(&d)) + 2);
    pf();//D::fd
    pf = (Fun) * ((int*)(*(int*)(&d)) + 3);
    pf();//D::gd
}

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

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

相关文章

页面访问升级出错怎么解决

相信大家在访问网站的时候时常会遇到页面访问界面升级&#xff0c;暂时不可能进行访问操作&#xff0c;可能遇到这种情况很多小伙伴们都不知道怎么版&#xff0c;其实互联网网页在正常使用过程中是不会出现这种问题的。那么如果遇到页面访问界面升级怎么办?页面访问界面升级通…

TryHackMe-Binex

Binex 枚举计算机并获取交互式 shell。利用 SUID 位文件&#xff0c;使用 GNU 调试器利用缓冲区溢出并通过 PATH 操作获得根访问权限。 端口扫描 循例 nmap SMB枚举 题目给了提示&#xff1a;Hint 1: RID range 1000-1003 Hint 2: The longest username has the unsecure pa…

面试中问你查看日志的命令,可不能只说tail,cat,more

首选&#xff0c;如何查看日志&#xff1a; 很多初级测试人员&#xff0c;在进行执行测试用例这个步骤时&#xff0c;发现bug&#xff0c;不能更加的准确去定位bug&#xff0c;在这样的情况下就可以打开Linux服务器&#xff0c;敲命令查看操作进行中的实时日志&#xff0c;当系…

用arthas轻松排查线上问题

你是否在项目中会碰到以下一些问题&#xff1a; 在代码中打印各种日志来排查&#xff0c;比如方法的入参&#xff0c;出参&#xff0c;及在方法体中打印日志判断走哪行代码还有你觉得代码没问题&#xff0c;可是运行出现却是以前的bug&#xff0c;感觉代码没修改&#xff0c;或…

120.(leaflet篇)区域下钻,区域钻取

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>

【RocksDB】Ubuntu20.04下编译rocksdb

前言&#xff1a; 我在刚学rocksdb的时候是在2022年&#xff0c;但是网上的资源很少&#xff0c;查了好久才把rocksdb安装成功&#xff0c;在这里向大家分享一下我的经历&#xff0c;安装过程中也报了很多错误&#xff0c;希望大家不要迷路 首先 在虚拟机里面安装依赖的包以…

python List和常用的方法

List&#xff1a;列表中包含多个数据&#xff0c;数据之间使用逗号分隔&#xff0c;索引从0开始。 空列表&#xff1a; dir&#xff1a;查看列表的所有方法 List常用方法&#xff1a;insert、append&#xff0c;extend、del、remove、pop、clear、count、index 增加insert(索引…

健身房戴耳机的人都喜欢戴哪款耳机健身、最好用健身耳机推荐

对于喜欢健身和运动人群来说&#xff0c;耳机可谓是重中之重了&#xff0c;带上耳机 听着喜欢的音乐&#xff0c;沉浸在自己的世界中&#xff0c;训练状态直接拉满…但是能适合运动佩戴的耳机真的不多&#xff0c;这类耳机要同时具备舒适度、防水性、稳固性、高续航等等性能&am…

coreldraw2023安装包下载及新功能介绍

对于广告标识业来说 coreldraw这个软件&#xff0c;对我们来说绝对不陌生&#xff0c;我从2008年开始接触到广告制作&#xff0c;到现在已经13多年了&#xff0c;从一开始的coreldraw 9红色的热气球开始。就被这个强大的软件所吸引&#xff0c;他有强大的排榜功能已经对位图的处…

zigbee 抓包软件Ubiqua使用详解

zigbee抓包软件使用&#xff08;Ubiqua Protocol Analyzer&#xff09; 添加Zigbee sniffer Dongle设备 add Device>vendor选择Texas Instruments>选择Texas Instruments CC2531>add Device 设置信道 右键设置需要抓包的信道 设置秘钥 单击主菜单Tools>Opt…

arm64虚拟化学习笔记

各种虚拟化对比 虚拟化种类优缺点实现硬件加速虚拟化性能最好&#xff0c;最贵1.vcpu 2.内存stage2 3.虚拟中断 4.arch time全虚拟化纯软件实现&#xff0c;性能差1.qemu串口 2.qemu磁盘半虚拟化软件实现复杂1.Virtio block 设备 2.Virtio net 设备io虚拟化加速移植性差1.PCI设…

java是编译型语言还是解释型语言?

基本概念 什么是编译型语言&#xff1f;编译型语言的首先将源代码编译生成机器语言&#xff0c;再由机器运行机器码&#xff08;二进制&#xff09;&#xff0c;比如C和C. 编译型语言&#xff1a;程序在执行之前需要一个专门的编译过程&#xff0c;把程序编译成 为机器语言的文…

mysql一explain结果分析

1. EXPLAIN简介 使用EXPLAIN关键字可以模拟优化器执行SQL查询语句&#xff0c;从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈。 ➤ 通过EXPLAIN&#xff0c;我们可以分析出以下结果&#xff1a; 表的读取顺序数据读取操作的操作类型哪些索引可…

【LeetCode】背包问题总结

文章目录一、背包能否装满&#xff1f;416. 分割等和子集1049. 最后一块石头的重量 II二、装满背包有几种方法&#xff1f;494. 目标和518.零钱兑换II377. 组合总和 Ⅳ70. 爬楼梯三、背包装满的最大价值474.一和零四、装满背包最小物品数322. 零钱兑换279.完全平方数一、背包能…

win10+python3.6+cuda9+pytorch1.1.0安装

为了让torch可以使用显卡GPU加速&#xff0c;需要安装对应版本的cudatoolkit和pytorch。这里我的nvidia显卡驱动是9.1版本&#xff0c;只能安装cudatoolkit9。 一般支持gpu加速的显卡大部分都是英伟达nvidia系列&#xff0c;都自带了nvidia驱动&#xff0c;所以不需要安装nvidi…

一次失败的面试经历:我只想找个工作,你却用面试题羞辱我!

金三银四近在咫尺&#xff0c;即将又是一波求职月&#xff0c;面对跳槽的高峰期&#xff0c;很多软件测试人员都希望能拿一个满意的高薪offer&#xff0c;但是随着招聘职位的不断增多&#xff0c;面试的难度也随之加大&#xff0c;而面试官更是会择优录取小王最近为面试已经焦头…

大数据处理学习笔记1.7 Scala类与对象

文章目录零、本节学习目标一、类&#xff08;一&#xff09;类的定义&#xff08;二&#xff09;类的实例化二、单例对象&#xff08;一&#xff09;单例对象概念&#xff08;二&#xff09;案例演示三、伴生对象&#xff08;一&#xff09;伴生对象概念&#xff08;二&#xf…

C++ vector学习与使用

本文皆在vs2015下运行&#xff0c;操作系统不一样结果可能有出入1.vector的介绍及使用1.1 vector的介绍string&#xff1a;动态类型的顺序表&#xff0c;只能存储charvector&#xff1a;动态类型的顺序表&#xff0c;任意类型的元素都可以存储endofstorage表示vector底层空间的…

Java_面向对象

Java_面向对象 1.面向对象概述 ​ 面向对象是一种符合人类思想习惯的编程思想。显示生活中存在各种形态的不同事物&#xff0c;这些食物存在着各种各样的联系。在程序中使用对象来映射现实中的事物&#xff0c;使用对象的关系来描述事物之间的关系&#xff0c;这种思想就是面…

如何使用码匠连接 Redis

目录 在码匠中集成 Redis 在码匠中使用 Redis 关于码匠 Redis 是由 Salvatore Sanfilippo 用 C 语言开发的一款开源的、高性能的键值对存储数据库&#xff0c;它采用 BSD 协议&#xff0c;为了适应不同场景下的存储需求&#xff0c;提供了多种键值数据类型。到目前为止&…