Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Gcc如何将虚拟方法解析为已解析的普通方法_C++_Virtual - Fatal编程技术网

C++ Gcc如何将虚拟方法解析为已解析的普通方法

C++ Gcc如何将虚拟方法解析为已解析的普通方法,c++,virtual,C++,Virtual,拥有 方法指针(最终为虚拟) 类的类型 我需要将虚拟呼叫转换为非虚拟呼叫。因此,将虚拟指针转换为解析指针 问题是:我如何做到这一点,例如在GCC中(如果没有标准提供的方法)。我不想像下面描述的那样使用黑客,但只是一些隐藏在包含的文件中的调用 为了澄清这个问题,我将解释到目前为止在调试GCC编译的汇编代码时所看到的情况。 我已经看到,通用方法指针包含两个数据: 指向该方法的“指针” 最终添加到类实例起始地址的偏移量 当涉及多重继承时,以及第二个或更多父类的方法(如果应用于它们的对象,它们的

拥有

  • 方法指针(最终为虚拟)
  • 类的类型
我需要将虚拟呼叫转换为非虚拟呼叫。因此,将虚拟指针转换为解析指针

问题是:我如何做到这一点,例如在GCC中(如果没有标准提供的方法)。我不想像下面描述的那样使用黑客,但只是一些隐藏在包含的文件中的调用

为了澄清这个问题,我将解释到目前为止在调试GCC编译的汇编代码时所看到的情况。 我已经看到,通用方法指针包含两个数据:

  • 指向该方法的“指针”
  • 最终添加到类实例起始地址的偏移量
当涉及多重继承时,以及第二个或更多父类的方法(如果应用于它们的对象,它们的数据将位于不同的起点)使用偏移量

指向该方法的“指针”如下所示:

  • 如果“指针”为偶数,则将其解释为正常(非虚拟)函数指针
  • 如果“指针”为奇数,则应减去1,剩余值应为0或4或8或12(假设指针大小为4字节)
  • 前面的编码显然假设所有正常方法都是从偶数地址开始的(因此编译器应该将它们对齐到偶数地址)。 该偏移量是vtable中的偏移量,在vtable中可以找到“实”非虚方法指针的地址

    因此,满足我要求的一种方法是:

    创建所需类型的虚拟对象,获取其地址,在其数据的开头有指向vtable的指针,get it

    获取方法指针,分为方法指针(地址或索引和偏移量)。将偏移量添加到对象地址。 通过查找将索引(如果方法是虚拟的)转换为非虚拟方法

    实现所述内容并用于回答另一个相关但略有不同的问题([如何获取指向虚拟成员函数的“直接”函数指针?][1])的代码如下:


    看起来你想要的是
    mem\u fn
    bind
    或仅仅是一个lambda。怎么不能满足你的需要?我给出的标题是误导性的和错误的。我的具体需要是我有一些简单的旧结构,有一个专有字段(例如,一个字节)这表明了它们在少数类型中的类型。这些不同的结构没有任何虚拟方法,而是具有相同名称和函数的方法。因此,这些结构有一个方法指示它们的大小和其他特征。我如何能够迭代它们(都是不同类型的)还能够调用常用方法吗?简单的答案是你不能“迭代它们”C++是强类型的,所以你不能将它们全部收集到容器中而不将它们转换成 Value*/Cudio>,甚至你也不知道你拥有什么类。这听起来好像你寻找的一部分可能是模板:<代码>模板无效CALMM(T&FoO){Fo.M.());为了能够在结构上进行迭代,您需要实现某种类型的类型擦除。我建议您看一看:尽管动机不同,但所选择的解决方案可能与您所追求的非常接近。如果您觉得您的标题和描述可以改进,最好对其进行编辑,而不是在com中添加解释(哦,如果您的指针强制转换导致了一些未定义行为的情况,我也不会感到惊讶。)
    #include <stdio.h>
    #include <string.h>
    #include <typeinfo>
    #include <typeindex>
    #include <cstdint>
    
    struct Animal {
        int weight = 0x11111111;
        virtual int mm() {printf("Animal1 mm\n");return 0x77;};
        virtual int nn() {printf("Animal1 nn\n");return 0x99;};
    };
    struct Tiger : Animal {
        int weight = 0x22222222, height = 0x33333333;
        virtual int mm() {printf("Tigerxx\n");return 0xCC;}
        virtual int nn() {printf("Tigerxx\n");return 0x99;};
    };
    typedef int (Animal::*methodPointerT)();
    
    typedef struct {
        void** functionPtr;
        size_t offset;
    } MP;
    
    void devirtualize(methodPointerT& mp0,const Animal& a) {
        MP& t = *(MP*)&mp0;
        if ((intptr_t)t.functionPtr & 1) {
            size_t index = (t.functionPtr-(void**)1); // there is obviously a more
            void **vTable = (void**)(*(void**)&a);    // efficient way. Just for clarity!
            t.functionPtr = (void**)vTable[index];
        }
    };
    
    int main()
    {
        Animal x;Tiger y;
        methodPointerT mp1 = &Animal::nn;
    
        (x.*mp1)(); (y.*mp1)();
    
        devirtualize(mp1,x);
    
        (x.*mp1)(); (y.*mp1)();
    }
    
    Animal1 nn
    Tigerxx
    Animal1 nn
    Animal1 nn