返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >【C++】多态(下)
  • 476
分享到

【C++】多态(下)

c++开发语言java 2023-08-17 15:08:04 476人浏览 泡泡鱼
摘要

文章目录 1.单继承中的虚函数表整体代码用程序打印虚表如何寻找到虚表地址虚表存在哪里? 2.多继承中的虚函数表整体代码寻找虚表地址注意事项多继承重写后的func1地址为什么不同?ptr1调用函数——一次jmpptr2 调用函数

1.单继承中的虚函数表

整体代码

#includeusing namespace std;class Base{public:    virtual void Func1()    {        cout << "Base::Func1()" << endl;    }    virtual void Func2()    {        cout << "Base::Func2()" << endl;    }    void Func3()    {        cout << "Base::Func3()" << endl;    }private:    int _b = 1;};class Derive : public Base{public:    virtual void Func1()    {        cout << "Derive::Func1()" << endl;    }    virtual void Func4()    {        cout << "Base::Func4()" << endl;    }private:    int _d = 2;};typedef void(*VF_PTR)();    //  typedef void(*)() VF_PTR;void PrintVFTable(VF_PTR table[])//函数指针数组{    int i = 0;    for (i = 0; table[i] != nullptr; i++)    {        printf("[%d]:%p\n",i, table[i]);        VF_PTR f = table[i];        f();    }}int main(){    Base b;    Derive d;    PrintVFTable((VF_PTR*)*(int*)&b);    cout << endl;    PrintVFTable((VF_PTR*)*(int*)&d);    return 0;}

在子类中实现一个虚函数Func4,但是不构成重写



Func4函数并没有进入虚表中


通过查询内存发现,虚表指针中存在三个地址,而其中两个正好为监视中的两个地址
猜测 0x00c4146a 就是Func4的地址

用程序打印虚表

虚表本质是一个函数指针数组

VS中在数组最后放了一个nullptr,这样就可以解决在不同虚表中的个数不同的问题


typedef一个函数指针 为VF_PTR


正常来说 要写成将VF_PTR放在后面

但是由于函数指针的特殊性,定义变量都要放在中间


如何寻找到虚表地址

想要虚表的地址,就可以通过找到虚表的指针
而这个虚表指针在对象中,这个指针在对象的前4个(32位)或者8个字节(64位)上面


以32位为例,如何取对象的前4个字节

强制转换为int*


* (int* )&b
首先取到Base* ,将其强制转换为int*,代表前四个字节的地址,再解引用是int类型,把前四个字节取出来
但是由于PrintVFTable函数参数是 函数指针数组


(VF_PTR*) * (int *)&b
如果这个数组是int类型,就需要 一个int * 指针去指向
同理 ,该数组为 VF_PTR类型,需要一个VF_PTR *指针去指向
所以需将 int 类型 再次强制转换为 VF_PTR * ,使其指向这个数组


缺陷
但是这种写法具有一定的局限性,只能在32位跑,因为32位指针大小为4个字节
而64位下就不行了,64位下指针大小为8个字节


在这里插入图片描述

运行程序打印虚表,确实了解到多了一个地址



把虚表的地址拿出来赋给函数指针,用函数指针去调用函数
这里发现 监视中没有出现的地址确实是Func4函数的地址

虚表存在哪里?

由于常量区地址与虚表的地址最为接近,所以说明虚表在常量区/代码段上

2.多继承中的虚函数表

整体代码

class Base1 {public:    virtual void func1() { cout << "Base1::func1" << endl; }    virtual void func2() { cout << "Base1::func2" << endl; }private:    int b1;};class Base2 {public:    virtual void func1() { cout << "Base2::func1" << endl; }    virtual void func2() { cout << "Base2::func2" << endl; }private:        int b2;};class Derive : public Base1, public Base2 {public:    virtual void func1() { cout << "Derive::func1" << endl; }    virtual void func3() { cout << "Derive::func3" << endl; }private:    int d1;};typedef void(*VF_PTR)();    //  typedef void(*)() VF_PTR;void PrintVFTable(VF_PTR table[])//函数指针数组{    int i = 0;    for (i = 0; table[i] != nullptr; i++)    {        printf("[%d]:%p->", i, table[i]);        VF_PTR f = table[i];        f();    }}int main(){    Derive d;    PrintVFTable(  (VF_PTR*) *(int*) &d);    cout << endl;        Base2* ptr2 = &d;    PrintVFTable((VF_PTR*)*(int*)(ptr2));    return 0;}

寻找虚表地址

Derive 作为Base1 和Base2的子类,所以Derive内部有两张虚表


正常来说,Derive内部还存在一个func3函数,这个函数放在哪里了呢?
借助打印虚表来查看,这里的打印虚表依旧可以使用单继承中的那个



base1的虚表指针 正好在对象的前4个字节处,直接可以使用求出虚表指针 去指向base1的虚表


方法1 : base2的虚表指针 需要加上base1的大小

但是这里要注意一个问题,若写成 PrintVFTable((VF_PTR*)(int)( &d+ sizeof(Base1) ) )
写的并不对,d本身是一个Derive类型,&d后变为Derive* 的一个指针,+1 跳转的是Derive类型的字节大小
而该设计想要每次+1跳转1个字节,所以需要强制转换char*


方法2 :切片自动偏移



在这里插入图片描述
两种方法的结果都是一样的

注意事项

多继承派生类增加的的虚函数在第一个虚表中

多继承重写后的func1地址为什么不同?


ptr1调用函数——一次jmp

找到 Base1虚表里的地址 0x00e21230 ,再call这个地址
只需要jmp一次 就可以找到实际真正执行的函数地址
ptr1调用地址属于正常调用


ptr2 调用函数——多次jmp

ptr2调用地址,需要 多次jmp 才能找到真正的函数地址

ecx存的是this指针
ecx,8 目的是修正this指针的位置
最终Base1和Base2都是执行同一个函数的指令


  • ptr1->func1 调用的是子类的func1函数,ptr1指向调用对象的开始
  • ptr2并没有指向子类对象的开始,此时调用子类对象的func1函数,this指针指向中间的位置不对了,所以需要修正this指针,使之指向子类对象开始的地方

来源地址:https://blog.csdn.net/qq_62939852/article/details/129975414

--结束END--

本文标题: 【C++】多态(下)

本文链接: https://lsjlt.com/news/373034.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 【C++】多态(下)
    文章目录 1.单继承中的虚函数表整体代码用程序打印虚表如何寻找到虚表地址虚表存在哪里? 2.多继承中的虚函数表整体代码寻找虚表地址注意事项多继承重写后的func1地址为什么不同?ptr1调用函数——一次jmpptr2 调用函数...
    99+
    2023-08-17
    c++ 开发语言 java
  • 【C++】多态
    🌇个人主页:平凡的小苏 📚学习格言:命运给你一个低的起点,是想看你精彩的翻盘,而不是让你自甘堕落,脚下的路虽然难走,但我还能走,比起向阳而生,我更想尝试逆风翻盘。 🛸C++专栏:C++内功...
    99+
    2023-08-17
    c++ 开发语言
  • C#多态详解
    目录1.定义2.实现多态的两个因素3.案例4、使用多态的好处5、string类1、值类型2、引用类型6.运算符重载:总结1.定义 多态是同一个行为具有多个不同表现形式或形态的能力。 ...
    99+
    2024-04-02
  • C++:多态讲解
    多态 1.多态的概念2.多态的定义和实现2.1多态构成条件2.2虚函数2.3虚函数的重写(覆盖)2.4 C++11 override 和 final2.5重载、重写(覆盖)、隐藏(重定义)的对...
    99+
    2023-10-19
    c++ 开发语言 学习方法 笔记 经验分享
  • C/C++使用C语言实现多态
    目录1.多态的概念1.1什么是多态?1.2为什么要用多态呢?1.3多态有什么好处?2.多态的定义及实现2.1继承中构成多态的条件2.2虚函数2.3虚函数的重写2.4C++11 ove...
    99+
    2024-04-02
  • C++中的多态详谈
    目录1. 多态概念1.1 概念2. 多态的定义及实现2.1 多态的构成条件2.2 虚函数2.3 虚函数的重写2.4 代码示例2.5 虚函数重写的两个例外2.6 C++11 overr...
    99+
    2024-04-02
  • C#多态如何实现
    小编给大家分享一下C#多态如何实现,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!C#实现多态主要有3种方法,虚方法,抽象类,接口1 虚方法在父类的方法前面加关键字...
    99+
    2023-06-14
  • C#多态性是什么
    这篇文章主要介绍“C#多态性是什么”,在日常操作中,相信很多人在C#多态性是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#多态性是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!多态是面向对象编...
    99+
    2023-06-17
  • C++多态如何使用
    本文小编为大家详细介绍“C++多态如何使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“C++多态如何使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。多态多态离不开继承,首先来定义一个基类 Anim...
    99+
    2023-07-02
  • c++多态如何实现
    多态是面向对象编程中允许对象具有不同形式或行为的一种机制。c++ 中的多态通过虚函数、抽象类、纯虚函数和动态绑定实现。虚函数允许派生类重新定义基类方法,抽象类包含必须在派生类中重新定义的...
    99+
    2024-04-22
    c++
  • C/C++多态原理实例分析
    本篇内容介绍了“C/C++多态原理实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!多态面向对象编程有三大特性:继承、封装和多态。其中,...
    99+
    2023-07-02
  • C/C++多态深入探究原理
    目录多态虚表和虚表指针多态 面向对象编程有三大特性:继承、封装和多态。 其中,多态又分为编译时多态和运行时多态。编译多态是通过重载函数体现的,运行多态是通过虚函数体现的。 多态是如何...
    99+
    2024-04-02
  • C++超全面讲解多态
    目录多态的概念多态的定义及实现构成条件虚函数虚函数的重写虚函数重写的两个例外抽象类抽象类的概念接口继承和实现继承多态的原理虚函数表多态的原理多态的概念 概念:通俗的来说就是多种形态,...
    99+
    2024-04-02
  • C++多态的全面讲解
    目录1.多态的定义和实现多态的浅层理解多态的构成条件2.虚函数虚函数的重写规则虚函数重写条件的两个例外1.协变(返回值不同)2.析构函数的重写(函数名不同)3.C++11 overr...
    99+
    2024-04-02
  • C#多态性怎么理解
    这篇文章主要讲解了“C#多态性怎么理解”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#多态性怎么理解”吧!C#多态性的内涵实际就是通过继承,一个类可以用作多种类型:可以用作它自己的类型、任...
    99+
    2023-06-17
  • C#多态是什么意思
    本篇内容介绍了“C#多态是什么意思”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、什么是C#多态?面向对象程序设计中的另外一个重要概念是多...
    99+
    2023-06-17
  • C++中怎么实现多态
    C++中怎么实现多态,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。实现了C++多态 2 5 1 6#include < iostream>&nb...
    99+
    2023-06-17
  • C++多态的示例详解
    目录案例一:计算器案例要求代码实现运行效果案例二:制作饮品案例要求代码实现运行效果案例三:电脑组装案例要求代码实现运行效果今天就以三个案例来把C++多态的内容结束。第一个案例就是用多...
    99+
    2024-04-02
  • c#基础学习之多态
    最近在看一本书《你必须知道的.Net》,书涵盖的内容比较多,对于c#,.Net平台以往所学的零散东西有了慢慢的总结和新的认识。把一些基础的东西记录于此。 先说说多态吧: 1.基类继承...
    99+
    2022-11-15
    c# 多态
  • 如何实现C#继承与C#多态
    这篇文章主要讲解了“如何实现C#继承与C#多态”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何实现C#继承与C#多态”吧!在C#中实现OOP思想,丝毫不逊色于Java,下面我通知两句话来帮...
    99+
    2023-06-17
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作