我试图访问 C++ 多态 class 的 vtable,但由于核心转储而失败,为什么?

I tried to visit vtable of a C++ polymorphic class, but failed with core dump, why?

我想用一个小程序来检测vtable的特性。我知道对于大多数流行的编译器,它们将生成其头部前导 size_t 的对象作为指向 vtable 的指针。所以我尝试转换这个指针并用它来直接调用函数。

typedef void (*pf)();
struct C
{
     virtual void f(){
       printf("weird\n");
     }
};
int main()
{
     C c1;
     C* p=&c1;
     pf* pvtable=(pf*)p;
     pf func1=pvtable[0];
     (*func1)();
     return 0;
}

我希望 (*func1)() 能够打印出 "weird"。但实际结果是核心转储。

我的程序哪里出错了? 谢谢

更新:

你这里有误:

pf* pvtable=(pf*)p;

您正在将指向对象 C 的指针转换为指向 vtable 的指针。因此,您将 C 对象的内容解释为 vtable。相反,您需要更进一步地进行间接访问;将指向 C 的指针转换为指向 vtable 的指针并取消引用它:

pf* pvtable=*(pf**)p;

通过这种方式,您将跟随存储在 C 对象开头的指针指向实际的 vtable。


我原来的答案重写了更多:

#include <iostream>

struct C
{
    virtual void f()
    {
        std::cout << "weird" << std::endl;
    }
};

typedef void** C_vtable;
typedef void (C_f)(C* thiz);

int main()
{
    // Create the object on stack
    C c1;

    // Reinterpret its address to an address of a virtual table and dereference it.
    C_vtable vtable = *reinterpret_cast<C_vtable*>(&c1);

    // Pick the first pointer from the virtual table and reinterpret it as our function
    C_f *func1 = reinterpret_cast<C_f*>(vtable[0]);

    // Call it
    (*func1)(&c1);

    return 0;
}

这至少适用于 Linux 上的 gcc 和 clang,也可能适用于其他编译器。但它取决于实现!