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,访问该地址。并将该地址转换为函数指针:

     

      调用后进入函数体

     

  • 相关阅读:
    ios 数据类型转换 UIImage转换为NSData NSData转换为NSString
    iOS UI 12 block传值
    iOS UI 11 单例
    iOS UI 08 uitableview 自定义cell
    iOS UI 07 uitableviewi3
    iOS UI 07 uitableviewi2
    iOS UI 07 uitableview
    iOS UI 05 传值
    iOS UI 04 轨道和动画
    iOS UI 03 事件和手势
  • 原文地址:https://www.cnblogs.com/hgwang/p/9649178.html
Copyright © 2011-2022 走看看