`vcall'{0,{flat}}'在下面的示例中表示什么?

时间:2009-03-13 17:22:15

标签: c++ visual-c++

我不确定问题是否已经解决。我正在检查堆栈溢出功能之一并得到了这个疑问。

让我们先检查一下代码:

#include <string>
#include <map>
#include <iostream.h>

class MyClass
{
public:

    virtual  int Func()
    {
        return 0;
    }

    int Func2()
    {
        return 0;
    }

};

class MyClass2 :  public MyClass
{
public:

    int Func( )
    {
        return 1;
    }

    int Func2()
    {
        return 1;
    }

};

class Processor
{
 private:
      typedef int (MyClass::*MemFuncGetter)();
      static std::map<std::string, MemFuncGetter> descrToFuncMap;

 public:
        static void Initialize();
        void Process(MyClass* m, const std::string&);

};

std::map<std::string, Processor::MemFuncGetter> Processor::descrToFuncMap;
void Processor::Initialize()
{

     descrToFuncMap["Func"]=&MyClass::Func;
     descrToFuncMap["Func2"]=&MyClass::Func2;
};

void Processor::Process(MyClass* ms, const std::string& key)
{
    std::map<std::string, MemFuncGetter>::iterator found = descrToFuncMap.find(key);
     if(found != descrToFuncMap.end())
     {
        MemFuncGetter memFunc = found->second;
        int dResult = (ms->*memFunc)();
        cout << "Result is : "<< dResult <<endl;
      }
 }


int main(int argc, char* argv[])
{
    Processor::Initialize();
    Processor p;

    MyClass *pMC2 = new MyClass2;
    p.Process(pMC2, "Func");
    p.Process(pMC2, "Func2");

    delete pMC2;
    pMC2 = NULL;

    return 0;
}

在此示例中,结果符合预期:

Result is : 1
Result is : 0

但是当我使用VC 6调试器调试并在Processor :: Process中观察到 memFunc 的值并找到以下值时:

在p.Process(pMC2,“Func”)中;调用

memFunc 0x004011bd [thunk]:`vcall'{0,{flat}}' 

在p.Process(pMC2,“Func2”)中;调用

memFunc 0x0040118b MyClass::Func2(void)

我不理解“[thunk]:`vcall'{0,{flat}}”中的 thunk flat ? 任何人都可以帮我理解这里的内部结构吗?

2 个答案:

答案 0 :(得分:3)

对于WikiPedia上的thunk意味着什么,有一个非常彻底的解释

http://en.wikipedia.org/wiki/Thunk

thunk的要点是在运行时访问C ++虚拟表的机制。设置为对象的运行时类型调用适当的虚函数。

关于vcall {0,{flat}}意味着什么,我不是100%肯定。我的猜测是它报告了thunk访问该方法的值。

  • 0:vtable中的偏移
  • {flat}:继承层次结构是平的而不是多个

答案 1 :(得分:1)

不同的符号是因为成员函数指针需要能够处理各种虚拟和非虚拟成员函数(尽管不是静态成员函数),并且它需要能够通过各种形式处理属于该类的成员函数继承(公共,私有和/或虚拟)。

我遇到的最好的文章解释了成员函数指针的工作原理是Doug Clugston关于代码项目的"Member Function Pointers and the Fastest Possible C++ Delegates"

  

您可能猜测“成员函数指针”就像普通函数指针一样,只保存代码指针。你错了。在几乎所有编译器上,成员函数指针大于函数指针。最奇怪的是,在Visual C ++中,成员函数指针的长度可能是4,8,12或16个字节,具体取决于与其关联的类的性质,并取决于使用的编译器设置!成员函数指针比您预期的更复杂。

这不容易阅读,但值得 - 在其他任何地方都很难找到这些信息。给这篇文章一个好的阅读可能会让你深入了解调试器在向你显示的内容时的真实含义

[thunk]:`vcall'{0,{flat}}'

JaredPar's answer可能非常重要 - Clugstons的文章将为您提供其余内容。