多重继承

多重继承是指C++类同时继承两个类或两个以上的类。

class Test
{
public:
int num1;
Test()
{
num1 = 1;
}
virtual void Proc1();
virtual void Proc2(); }; class Test1
{
public:
int num2;
Test1()
{
num2 = 2;
}
virtual void Proc3();
virtual void Proc4();
}; class Test2:public Test, public Test1
{
public:
int num3;
Test2()
{
num3 = 3;
}
virtual void Proc2();
virtual void Proc4();
virtual void Proc5();
}; Test2 test;

对于多重继承而言,对象会有多个虚表指针。首先调用第一个继承的类Test的构造函数(传递的this指针就是对象首地址),接着会调用第二个继承类Test1的构造函数(传递的this指针是对应类数据在对象中的地址,将对象首地址偏移指定地址后传入。这样就可以避免访问到Test类的成员变量)。接着回到Test2的构造函数中初始化两个虚表指针(也就是说其含有两个虚表)。

我们看一下调用完Test2的构造函数后对象内存处的值,发现会有两个虚表指针。分别在连个父类的前4个字节中。



查看两个虚表发现,第一个虚表中存储的是继承第一个类的虚函数地址,如果其虚函数在子类Test2中被覆盖则地址也会被覆盖。第二个虚表中存储的是继承第二个类的虚函数地址,同样其虚函数在子类Test2中被覆盖则地址也会被覆盖。那么如果在Test2类中新增的虚函数其地址存放到哪呢?一般编译器都会将其存在第一个虚表中靠后的地址处。

菱形继承


class Test
{
public:
int num1;
virtual void Proc1();
virtual void Proc2();
virtual void Proc3();
}; class Test1:virtual public Test
{
public:
int num2;
Test1(){
num2 = 0x02;
num1 = 0x01;
};
virtual void Proc1();
virtual void Proc4();
}; class Test2:virtual public Test
{
public:
int num3;
Test2(){
num3 = 0x03;
} }; class Test3:public Test1, public Test2
{ public:
int num4;
Test3(){
num4 = 0x04;
} };



上面的示例就是一个典型的菱形继承,且为了保证Test数据成员在Test3类对象中的唯一性,需要Test1继承Test(Test2继承Test)时采用虚继承。



菱形继承内存的布局如下,其有三个虚表指针。父类除了包含虚表指针外还包含一个vt_offset域,此域包含两个字段,第一个字段是本类虚表指针相对于vt_Offset域的偏移,第二个字段是本类的父类(祖父类)的虚表指针相对于vt_offset域的偏移。

注意两个父类虚表指针中包含的是父类中新定义的虚函数,如果其覆盖祖父类中的虚函数其地址应该在祖父类的那个虚表指针中。其中子类也会覆盖父类中的虚函数,那如果其新增虚函数地址应该放在哪呢?编译器一般是将其放在第一个继承的类的虚表指针中,也就是虚表指针1指向的虚表靠后的位置。

调用两个父类或祖父类的构造函数时都会将对象首地址往后偏移到对应的类处的地址后当this指针传递,这样可以在父类或祖父类的构造函数中直接通过偏移访问其自己的类成员。那么现在有个问题在父类的构造函数中访问子类的成员变量应该如何访问呢,祖父类的数据成员在对象的最底部如果单单利用顺序偏移的关系是无法正确访问的,实际其实利用vt_offset域的第二个字段父类对应虚表指针相对于vt_offset的偏移来访问的,因为对于祖父类而言其虚表指针后面跟着的就是自己的成员变量。

参考《C++反汇编与逆向分析技术揭秘》

C++逆向分析----多重继承和菱形继承的更多相关文章

  1. Python多重继承之菱形继承

    继承是面向对象编程的一个重要的方式,通过继承,子类就可以扩展父类的功能.在python中一个类能继承自不止一个父类,这叫做python的多重继承(Multiple Inheritance ). 语法 ...

  2. C++反汇编第五讲,认识多重继承,菱形继承的内存结构,以及反汇编中的表现形式.

    C++反汇编第五讲,认识多重继承,菱形继承的内存结构,以及反汇编中的表现形式. 目录: 1.多重继承在内存中的表现形式 多重继承在汇编中的表现形式 2.菱形继承 普通的菱形继承 虚继承 汇编中的表现形 ...

  3. 《C++反汇编与逆向分析技术揭秘》之12——继承

    识别类和类之间的关系 在父类中声明为私有的成员,虽然子类对象无法直接访问,但是在子类对象的内存结构中,父类私有的成员数据依然存在. 在没有提供构造函数的时候,系统会尝试提供默认的构造函数: 当子类中没 ...

  4. C++反汇编第四讲,认识多重继承,菱形继承的内存结构,以及反汇编中的表现形式.

    目录: 1.多重继承在内存中的表现形式 多重继承在汇编中的表现形式 2.菱形继承 普通的菱形继承 虚继承 汇编中的表现形式 一丶多重继承在内存中的表现形式 高级代码: class Father1 { ...

  5. C++反汇编-菱形继承

    学无止尽,积土成山,积水成渊-<C++反汇编与逆向分析技术揭秘> 读书笔记.马上就要出差了,回来后接着写吧. 一.概述 菱形继承是最复杂的对象结构,菱形结构会将单一继承与多重继承进行组合. ...

  6. C++中的多重继承与虚继承的问题

    1.C++支持多重继承,但是一般情况下,建议使用单一继承. 类D继承自B类和C类,而B类和C类都继承自类A,因此出现下图所示情况: A          A \          / B     C ...

  7. C++反汇编与逆向分析技术揭秘

    C++反汇编-继承和多重继承   学无止尽,积土成山,积水成渊-<C++反汇编与逆向分析技术揭秘> 读书笔记 一.单类继承 在父类中声明为私有的成员,子类对象无法直接访问,但是在子类对象的 ...

  8. C++中的类继承(4)继承种类之单继承&多继承&菱形继承

    单继承是一般的单一继承,一个子类只 有一个直接父类时称这个继承关系为单继承.这种关系比较简单是一对一的关系: 多继承是指 一个子类有两个或以上直接父类时称这个继承关系为多继承.这种继承方式使一个子类可 ...

  9. c++继承汇总(单继承、多继承、虚继承、菱形继承)

    多重继承中,一个基类可以在派生层次中出现多次,如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,则在最终的派生类中会保留该间接共同基类数据成员的多分同名成员.C++提供虚基类的方法使得在 ...

随机推荐

  1. 通俗易懂,android是如何管理内存的

    封面来源:https://medium.com/android-news/android-performance-patterns-rescue-tips-8c1e4c7cb1f0 前言 很高兴遇见你 ...

  2. 我叫小M,立志建立MySQL帝国。

    我是小M,我在卡拉巴拉星球. 我喜欢数据,我立志成为一个数据管理者. 所以我来 Y 公司应聘,听说他们的数据量挺大的. 面试过程还是挺简单的. 我用 007 这三个数字就轻易打败了一堆吹嘘 996 的 ...

  3. C语言之预处理详解

    C语言之预处理详解 纲要: 预定义符号 #define #define定义标识符 #define定义宏 #define的替换规则 #与## 几点注意#undef 带副作用的宏参数 宏和函数的对比 命名 ...

  4. JS基础学习第一天

    JavaScript JavaScript负责页面中的的行为. 它是一门运行在浏览器端的脚本语言. JS的编写的位置 1.可以编写到标签的指定属性中 12 <button onclick=&qu ...

  5. 201871010129-郑文潇 实验二 个人项目—《D{0-1}背包问题 》项目报告

    项目 内容 课程班级博客链接 课程链接 这个作业要求链接 [作业要求](https://www.cnblogs.com/nwnu-daizh/p/14552393.html) 我的课程学习目标 1.掌 ...

  6. OOUnit3Summary

    一.JML基础梳理及工具链 jml语言基础 JML的全称是Java Modeling language,是一种行为接口规格语言,通过JML及其支持工具,不仅可以基于规格自动构造测试用例,还可用SMT ...

  7. LeetCode剑指Offer刷题总结(一)

    LeetCode过程中值得反思的细节 以下题号均指LeetCode剑指offer题库中的题号 本文章将每周定期更新,当内容达到10题左右时将会开下一节. 二维数组越界问题04 public stati ...

  8. Java 使用 Maven BOM 统一管理版本号

    一个中大型的 Java 项目往往包含若干 JAR 包,这些 JAR 包有着不同的版本号.如果这些 JAR 包单独发布,然后直接通过版本号引用相应的 JAR 包,不同版本的兼容性维护将变得十分麻烦.为了 ...

  9. java7与java9中的try-finally关闭资源

    1.java7中的try 在java7之前,对于一些需要使用finally关闭资源的操作,会显得很臃肿. try { // } catch(Exception e) { // } finally { ...

  10. 测试报告模板:HTMLTestRunner.py(新版)

    报告样式效果: 报告源码:HTMLTestRunner.py 1 """ 2 A TestRunner for use with the Python unit test ...