leg*_*ryz 1 c++ virtual-functions member-function-pointers c++14 virtual-table
我正在从虚拟表中的地址调用虚函数作为练习,以测试我对该概念的理解.但是,一旦我认为我在理解虚拟方法表时取得了突破,我就遇到了另一个我不明白的问题.
在下面的代码中,我创建了一个名为的类Car,它包含一个成员变量x和两个虚函数,第一个和第二个.现在,我通过黑客攻击虚拟表来调用这两个虚拟方法.第一个函数返回正确的答案,但第二个函数返回一些随机值或垃圾,而不是它初始化的内容.
#include <cstdio>
class Car
{
private:
int x;
virtual int first()
{
printf("IT WORKS!!\n");
int num = 5;
return num;
}
virtual int second()
{
printf("IT WORKS 2!!\n");
//int num = 5;
return x;
}
public:
Car(){
x = 2;
}
};
int main()
{
Car car;
void* carPtr = &car;
long **mVtable =(long **)(carPtr);
printf("VTable: %p\n", *mVtable);
printf("First Entry of VTable: %p\n", (void*) mVtable[0][0]);
printf("Second Entry of VTable: %p\n", (void*) mVtable[0][1]);
if(sizeof(void*) == 8){
printf("64 bit\n");
}
int (*firstfunc)() = (int (*)()) mVtable[0][0];
int x = firstfunc();
int (*secondfunc)() = (int (*)()) mVtable[0][1];
int x2 = secondfunc();
printf("first: %d\nsecond: %d", x, x2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果有人可以指出我做错了什么,我将不胜感激.此外,由于这在编译器中的工作方式不同,我使用c ++ 14 在http://cpp.sh/上进行测试.
该代码输出,其中"垃圾"第二输出可能会发生变化:
VTable: 0x400890
First Entry of VTable: 0x400740
Second Entry of VTable: 0x400720
64 bit
IT WORKS!!
IT WORKS 2!!
first: 5
second: -888586240
Run Code Online (Sandbox Code Playgroud)
方法确实通常实现为常规函数,但是它们需要接收this访问特定实例的数据的指针 - 事实上,当您在实例上调用方法时,指向实例的指针将作为隐藏参数传递.
在你的代码中你没有传入它,所以该方法只返回垃圾 - 它可能正在使用发生在寄存器或堆栈中的任何事情,就像它是实例指针一样; 你很幸运,它没有明显崩溃.
您可以尝试更改原型以接受Car*参数并传递&car给它,但它可能会也可能不会起作用,具体取决于编译器/平台使用的调用约定:
stdcall调用约定(或cdecl用于可变参数),但接收this指针ecx,通过常规函数调用无法模拟;cdecl函数处理,this隐式传递就像它是最后一个参数一样.| 归档时间: |
|
| 查看次数: |
138 次 |
| 最近记录: |