【问题标题】:understanding c++ vtables and RTTI理解 c++ vtables 和 RTTI
【发布时间】:2013-11-26 16:23:33
【问题描述】:



我最近在搞乱 vtables,以便更好地理解编译器/进程需要做什么来实现类和继承。

这就是我想要完成的: 我想编写自己的小 vtable,以便在对象上强制执行静态行为:

class A {
public:
    virtual void foo() { cout << "A.foo()" << endl; }
    virtual void bar() { cout << "A.bar()" << endl; }
};

class B : public A {
public:
    void foo() { cout << "B.foo()" << endl; }
    void bar() { cout << "B.bar()" << endl; }
};

typedef void (A::*func)();

int main() {
    A& b_as_a = *(new B());
    long* p = (long*)(&b_as_a);
    func* vtab = (func*)(p[0]);

    b_as_a.foo();
    b_as_a.bar();

    func* my_vtab = new func[4];

    my_vtab[0] = vtab[0]; // \  I added these lines in step two after i got an
    my_vtab[1] = vtab[1]; // /  access violation
    my_vtab[2] = &A::bar;
    my_vtab[3] = &A::foo;

    p[0] = (long)(my_vtab);

    b_as_a.foo();
    b_as_a.bar();

    delete[] my_vtab;
    delete &b_as_a;

    return EXIT_SUCCESS;
}

这里是g++ -std=c++11 -fdump-class-hierarchy的转储

Vtable for A
A::_ZTV1A: 4u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI1A)
16    (int (*)(...))A::foo
24    (int (*)(...))A::bar

Class A
   size=8 align=8
   base size=8 base align=8
A (0x0x7f40b60fe000) 0 nearly-empty
    vptr=((& A::_ZTV1A) + 16u)

Vtable for B
B::_ZTV1B: 4u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI1B)
16    (int (*)(...))B::foo
24    (int (*)(...))B::bar

Class B
   size=8 align=8
   base size=8 base align=8
B (0x0x7f40b60dfbc8) 0 nearly-empty
    vptr=((& B::_ZTV1B) + 16u)
  A (0x0x7f40b60fe060) 0 nearly-empty
      primary-for B (0x0x7f40b60dfbc8)


这不起作用......所以我研究了一下。
我找到了这篇文章:What is the first (int (*)(...))0 vtable entry in the output of g++ -fdump-class-hierarchy?
它解释了 vtable 中的前两个条目。我了解第一个条目的作用,但我所知道的第二个条目是,它是某种指向类信息的指针。
我想这就是它不起作用的原因。

剩下的问题是:
vtable 中的第二个条目有什么作用使下面的函数指针不再被读取???


额外信息:我在 openSuse 12.3 上使用 g++

【问题讨论】:

  • 我无法理解问题所在。你能进一步解释你的意思吗?
  • 这太复杂了。为什么要对抗语言?为什么不使用带有覆盖和函数指针或 lambda 的普通 C++?
  • 这不是/不应该用于生产或任何东西。这只是一个实验,以增加我对语言及其工作原理的理解。只是出于……好奇;)

标签: c++ g++ rtti vtable


【解决方案1】:

vptr 指向 vtable 中的第三项。你可以从你的类转储中看到:

    vptr=((& A::_ZTV1A) + 16u)

或通过将内存中的值与成员函数地址进行比较。

所以,你要修改的是前两项:

my_vtab[0] = &A::bar;
my_vtab[1] = &A::foo;

此外,不要使用成员函数指针构造新的 vtable,而是使用普通函数指针(甚至 void*)。例如。 :

typedef void (*func)();

或:

typedef void* func;

原因是成员函数指针已经处理了虚成员函数,因此不适合作为 vtable 中的条目(有关更多信息,请参阅问题 Why the size of a pointer to a function is different from the size of a pointer to a member function?,例如)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-07
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 2015-05-01
    • 2011-07-21
    • 2023-03-05
    相关资源
    最近更新 更多