2011-12-30 57 views
2

假设有一个名为Person的类,它包含一个名为age()的虚函数。根据语言语义,vtable是每个类而不是每个对象。它是每个对象的VPTR,并指向vtable。vtable中虚函数的地址

问题:

如果我建立这个程序(可以说main()的存在):

  1. 将虚函数表中创建即可以VTABLE自带存在W/O甚至创建一个对象?

  2. 编译器放入vtable for age()的地址是一种内存中的某种静态地址吗?

  3. 或者它是编译器内部创建一些对象来获取age()的地址(因为age()将在一些数据成员上工作,这些数据成员只有在构造对象时才会存在)或者有一些这背后的其他魔法?

按我的理解,答复如下:

  1. 不知道

我试图在上面运行的程序 “纳米” 刚看看我能不能找出虚拟表,但没有运气。有没有办法做到这一点?

请建议。

+4

这一切都取决于实现,所以你必须指定你使用哪个编译器,如果你想要一个实际的答案。 – 2011-12-30 19:06:33

+0

*根据语言语义* ...语言甚至没有提及*虚拟表*或*虚拟表指针*,而是可以用虚拟表实现的操作的语义(如在所有当前编译器中)或与任何其他方法 – 2011-12-30 19:12:12

+0

谢谢@EtiennedeMartel – 2011-12-30 21:17:55

回答

0

“根据语言语义,”没有vtable这样的东西。 C++规范没有详细说明如何实现虚拟调度。编译器可以使用vtables。或者可以使用别的东西;这取决于编译器。

当然,一个特定的编译器可以使用vtables。但它可以随心所欲地做任何事情;这是一个实现细节。总之,没有调查你正在使用的特定编译器,你就无法知道。

真的,这有什么关系吗?

+0

从Bruce Eckel,我了解实现,因此认为这是C++如何定义它的。但是,你是对的。这应该是编译器依赖的。感谢您纠正我的理解。 – 2011-12-30 21:13:57

1

所有这些答案都完全依赖于编译器。没有要求物理vtbl甚至存在;这只是执行该语言的一种非常常见的方式。但是对于这些,并没有普遍的ABI,并且这不像开发人员应该担心的那样。

+0

明白了,谢谢。 – 2011-12-30 21:16:16

3

因为它是定义所有的实现,我的回答描述了一些“共同实施”

  1. 的v表由操作系统存储在可执行文件就像机器代码本身,并加载到内存装载机。操作系统无需关心要加载的数据:字符串文字,机器代码,vtable,常量数据等等......

  2. 假设您有:

    struct A { 
        int x; 
        virtual void f() { cout << x; } 
    }; 
    
    void g(A* a) { a->f(); } 
    

    生成的代码看起来(语义)类似:

    // pseudocode, not C++ 
    struct A { 
        void *vtable; 
        int x; 
    }; 
    
    void A_f(A* this) { cout << this->x; } 
    
    void* A_vtable[] = { &A_f }; 
    
    void g(A* a) { ((void(*)(A*))(((void**)a->vtable)[0]))(a); } 
    

    所以,是的,它是静态数据。

    当然,上面的代码是非常简单的。要支持RTTI和虚拟继承,你必须做更复杂的事情。

  3. 我不明白你的意思,但号

+0

你有一个很好的解释。这也说明了我Q3以及:) – 2011-12-30 21:26:48

1

这是所有编译器相关的,你应该采取的全部答案,就像一种方式,它可以做到:

这个vtable是否会被创建,也就是说vtable是否可以创建,即使创建一个单独的对象?

取决于编译器和程序。例如,GCC将在翻译单元中创建vtable,其中定义了类定义中未定义的第一个虚拟函数(是否创建了任何对象),但在某些情况下可能根本不会生成vtable或者即使没有创建对象,它也可能会生成一个。

编译器放入vtable for age()的地址是一种内存中的一些静态地址吗?

这通常由链接器/加载程序解决。当程序被链接时,链接器通常会解析函数的(相对)地址,并将这些地址注入到vtable中作为第一步。当程序被加载到内存中时,这些地址被固定到函数所在的内存地址(这取决于加载程序会因执行而异)。

或者它是编译器在内部用于获得地址年龄()(因为年龄()将被工作的一些数据成员可进来存在一个对象被构造仅当)产生了一些对象或有这背后还有其他魔法?

我不太关注整个问题。编译器不会创建具有成员age类型的任何对象,只有在您的程序请求它时才会这样做。成员函数可能访问/修改给定类型的对象的数据成员,但是通过传递给所有非静态成员的隐式指针来处理对这些成员的访问。

+0

谢谢@David .. – 2011-12-30 21:28:32