zoukankan      html  css  js  c++  java
  • 探索C++虚函数

    探索C++虚函数

     1 测试环境

      各个编译器对虚函数的实现有各自区别,但原理大致相同。本文基于VS2008探索虚函数

    2 测试代码

     1 #pragma once
     2 #include <iostream>
     3 using namespace std;
     4 class C1
     5 {
     6 public:
     7     C1()
     8     {
     9         mem1 = 1;
    10         mem2 = 2;
    11     }
    12     virtual void f1()
    13     {
    14         cout << "this is C1 f1" << endl;
    15     }
    16     virtual void f2()
    17     {
    18         cout << "this is C1 f2" << endl;
    19     }
    20     virtual ~C1()
    21     {
    22         cout << "this is C1 deconstruction" << endl;
    23     }
    24     int mem1;
    25     int mem2;
    26 };
    27 
    28 typedef void (*Fun)(void);
    29 
    30 //调用虚函数
    31 template<class F>
    32 void CallVirtualFun(const int* p_virTableAddrPtr, const int index)
    33 {
    34     int funAddr = 0;            //定义函数地址数值,用int取函数地址
    35     int* p_funAddr = NULL;        //真实虚函数地址
    36     F fun = NULL;                //函数指针
    37 
    38     memcpy(&funAddr ,p_virTableAddrPtr + index, 4);        //从虚函数表中取函数地址,结果保存在funAddr
    39     p_funAddr = (int*)funAddr;    //将函数地址数值转换为函数地址
    40     fun = (F)p_funAddr;        //转函数指针
    41     fun();                        //调用函数
    42 }
    43 
    44 void VirtualFunByOffset()
    45 {
    46     C1 mC1;
    47     //取出类地址
    48     int* p_classAddr = (int*)(&mC1);
    49     //取出虚表的地址,类的前4个字节是虚表指针,首先取出虚表地址
    50     int virTableAddrInt = *p_classAddr;
    51     //根据虚表的地址访问虚表,虚表每一项都是函数指针,占有4个字节
    52     int* p_virTableAddrPtr = (int*)virTableAddrInt;
    53 
    54     //将虚函数地址转换为函数指针
    55     CallVirtualFun<Fun>(p_virTableAddrPtr, 0);    //调用虚函数表的第一个虚函数
    56     CallVirtualFun<Fun>(p_virTableAddrPtr, 1);    //调用虚函数表的第二个虚函数
    57 };

    3 类对象

     3.1 虚函数表总是在类对象的起始位置

     

    3.2 虚函数表中函数位置与声明顺序相关

       声明虚虚构,看出虚析构函数在虚函数表中第一个位置

      

       将虚析构挪到末尾处声明,看出虚析构在虚函数表末尾位置

     

    3.3 类对象模型

       C1为例,构建对象模型,如下图所示:

     

    • 类对象的最前面为指向虚表的指针(4个字节
    • 虚表的每一项对应类声明的虚函数指针(4个字节),因此,获取虚表的起始地址后,可以根据偏移获取到各个虚函数地址
    • 虚函数的指针指向虚函数,只要知道虚函数的格式(声明),就可以调用对应的虚函数

    4 代码调试访问虚表

      本册测试结构为

      首先创建一个类对象,通过类起始地址获取得到类的前4个字节,即虚表地址。

     

      拿到虚表地址后,查看虚表。函数指针每4个字节为1个单位,下面的虚表地址下共有3个虚函数,虚表以0结束。

     

      取得虚表的第一个函数,这里是C1::f1,地址是00 0a 10 c3,访问该地址。并将该地址转换为函数指针:

     

      调用后进入函数体

     

  • 相关阅读:
    mycat安装
    docker注册&打包
    docker的使用场景和背景了解
    解析nohup java -jar xxx &
    透明度百分比和十六进制对应关系
    android get cpu rate
    Cordova插件开发
    VectorDrawable在Android中的配置
    APK反编译后添加日志
    apk重新签名
  • 原文地址:https://www.cnblogs.com/hgwang/p/9649178.html
Copyright © 2011-2022 走看看