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