【问题标题】:Difference between address in VTABLE and direct address takeVTABLE 中的地址与直接地址取的区别
【发布时间】:2015-11-30 17:43:12
【问题描述】:
#include <iostream>
#include <vector>
using namespace std;

class Foo
{
public:
    virtual void f1()
    {
        cout << "Foo::f1()" << endl;
    }
    virtual void f2()
    {
        cout << "Foo::f2()" << endl;
    }
    virtual void f3()
    {
        cout << "Foo::f3()" << endl;
    }
};
int main()
{
    typedef void(*MethodFoo_f)();

    Foo* ptr = new Foo();

    cout << "Object address: " << ptr << endl;
    cout << "__vfptr: " << (int*)*((int*)ptr) << endl;

    for(int i = 0; i < 3; ++i)
    {
        int* e = (int*)*((int*)ptr) + i;
        cout << "Address from __vfptr " << e;
        auto t = &Foo::f1;
        switch(i)
        {
            case 0: t = &Foo::f1; cout << ", address from main " << (void*&)t << "  ";  break;
            case 1: t = &Foo::f2; cout << ", address from main " << (void*&)t << "  ";  break;
            case 2: t = &Foo::f3; cout << ", address from main " << (void*&)t << "  ";  break;

        }
        cout << "execute: ";
        auto func = (MethodFoo_f*)(e);
        (*func)();
    }

}

大家好,你能解释一下吗:为什么我们可以看到相同方法的地址不同。

Visual Studio 的示例输出

对象地址:007ADE28 __vfptr: 00E63B34

地址来自 __vfptr 00E63B34,地址来自主地址 00E51F23 执行: Foo::f1()

地址来自 __vfptr 00E63B38,地址来自主 00E51F1E 执行: Foo::f2()

地址来自 __vfptr 00E63B3C,地址来自主地址 00E51F19 执行: Foo::f3()

如果 VTABLE 调用转换为

objPointer->(__vfptr + methodIndex)()

为什么在表中,我们保存地址的修改值?

【问题讨论】:

  • vtables 的实现方式(如果使用的话)是特定于编译器的。你实际上会期待什么? "objPointer-&gt;(__vfptr + methodIndex)()" c++ 标准中哪里有这样的规定?还要检查指针算法,+ 可能与您在这里所期望的不同。
  • 一切似乎都很好。解释你的推理为什么你期望其他事情发生。
  • 我建议你先了解指向虚成员函数的指针是什么(以及它不是什么)。例如,它不能转换为指向非成员的指针。
  • 您似乎对底层实现做出了很多假设,从而产生了严重的未定义行为。但是您随后测试的平台非常适合您所有明显的假设。基于这些假设,一切都会发生。然后由于你真的没有说清楚的原因,你不喜欢那个输出。
  • 如果你真的想了解它是如何在这个特定的平台/编译器上实现的,你可以看看生成的汇编代码

标签: c++


【解决方案1】:

我终于意识到你想要什么,你缺少了一层间接性。

ptr 指向对象
(假设 32 位和许多其他你不应该真正假设的东西):
*((int*)ptr) 是 vtable 的地址
(int*)*((int*)ptr)*((int**)ptr) 是同一地址的转换
@987654325 @ 是 &amp; (*((int**)ptr))[i] 是 vtable 中的一个位置,您想要该位置的内容:
*((int*)*((int*)ptr)+i)(*((int**)ptr))[i]

func
MethodFoo_f 是指向函数的指针类型,func 是指向MethodFoo_f 的指针
因此,您希望每个函数的数字相同的是指向函数的指针和指向函数的简单指针。

我仍然不会猜到您从auto t = &amp;Foo::f1; 获得的指向函数的指针确实具有与void* 相同的内容,指向函数的实际代码。但至少在正确的间接级别下,您可以将其与那个进行比较。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-14
    • 2014-03-15
    • 1970-01-01
    • 2012-04-21
    • 1970-01-01
    • 1970-01-01
    • 2013-09-22
    相关资源
    最近更新 更多