2014-09-12 108 views
0

我只是迷惑不解以下几点:C++:在Visual Studio奇怪的虚成员函数指针2013

struct InterfaceABC { 
    virtual int printPolymorphic(int a) { 
     return a; 
    } 
} 

struct WithInterfaces : public InterfaceABC { 
    virtual int printPolymorphic(int a) { return a; } 
}; 

当我现在做的事:

address = &WithInterfaces::printPolymorphic; 

我在调试器中得到这样的:

0x012e52a9 {unittests.exe![thunk]:MockMe::WithInterfaces::`vcall'{4,{flat}}' }'} 

但是,以下invokation将不会落在那里:

((InterfaceABC*) new WithInterfaces())->printPolymorphic(3); 

的努力了一天后,我发现了如何“可靠”(鬼才)获得使用C++代码的实际虚拟地址,这给了我:

0x012e6ece {unittests.exe!MockMe::WithInterfaces::printPolymorphic(int)} 

那么我们有什么在这里?

WithInterfaces().printPolymorphic(3) 

将调用

0x012e6ece {unittests.exe!MockMe::WithInterfaces::printPolymorphic(int)} 

等都将

((InterfaceABC*)new WithInterfaces())->printPolymorphic(3); 

...

Visual Studio中实现存根功能justfor我:)吧?我感到受宠若惊......但

address = &WithInterfaces::printPolymorphic; 

这将不会给你的功能地址。它会给你一个从未被调用过的函数的地址,如果没有hackery,永远不会被调用。

任何人都有一些很好的想法,为什么这是?也许还有一些关于如何真正得到真正的地址的想法,而不写100行可怕的C + +疯狂,可能没有人,但我明白从所有的人将审查代码?也就是说,以符合标准的方式...

回答

2

WithInterfaces::printPolymorphic的地址给出了一个thunk,它在调用时根据对象的类型分派到正确的函数中进行调用。

如果您在对象上调用虚拟成员函数,编译器会发出代码来查找指向该对象的虚函数表(vtable)中正确实现的指针,然后调用该函数。

指向虚拟成员函数的指针封装了此行为,您通过查看生成的thunk将其明确化。

它会给你一个地址到这,不会被调用,而不两轮牛车永远不能被调用的函数。

但是,它的逻辑包含在对虚函数的每一次调用中。

+0

嗯哑我......对,如果你通过该地址的东西,它不知道它的虚拟功能。所以它只会传递对象指针,然后thunk会做虚拟的事情。似乎有点合乎逻辑。至少我一天的努力没有浪费。感谢您的澄清! – thesaint 2014-09-12 19:52:04