Does every object of virtual class have a pointer to vtable?

后端 未结 9 905
借酒劲吻你
借酒劲吻你 2020-12-14 10:54

Does every object of virtual class have a pointer to vtable?

Or only the object of base class with virtual function has it?

Where did the vtable stored? code

相关标签:
9条回答
  • 2020-12-14 11:36

    Not necessarily

    Pretty much every object that has a virtual function will have one v-table pointer. There doesn't need to be a v-table pointer for each class that has a virtual function that the object derives from.

    New compilers that analyse the code sufficiently may be able to eliminate v-tables in some cases though.

    For example, in a simple case: if you only have one concrete implementation of an abstract base class, the compiler knows that it can change the virtual calls to be regular function calls because whenever the virtual function is called it will always resolve to the exact same function.

    Also, if there's only a couple of different concrete functions, the compiler may effectively change the call-site so that it uses an 'if' to select the right concrete function to call.

    So, in cases like this the v-table isn't needed and the objects might end up not have one.

    0 讨论(0)
  • 2020-12-14 11:37

    All virtual classes usually have a vtable, but it is not required by the C++ standard and the storage method is dependent upon the compiler.

    0 讨论(0)
  • 2020-12-14 11:39

    To answer the question about which objects (instances from now on) have vtables and where, it's helpful to think about when you need a vtable pointer.

    For any inheritance hierarchy, you need a vtable for each set of virtual functions defined by a particular class in that hierarchy. In other words, given the following:

    class A { virtual void f(); int a; };
    class B: public A { virtual void f(); virtual void g(); int b; };
    class C: public B { virtual void f(); virtual void g(); virtual void h(); int c; };
    class D: public A { virtual void f(); int d; };
    class E: public B { virtual void f(); int e; };
    

    As a result, you need five vtables: A, B, C, D, and E all need their own vtables.

    Next, you need to know what vtable to use given a pointer or reference to a particular class. E.g., given a pointer to A, you need to know enough about the layout of A such that you can get a vtable that tells you where to dispatch A::f(). Given a pointer to B, you need to know enough about the layout of B to dispatch B::f() and B::g(). And so on and so on.

    One possible implementation could put a vtable pointer as the first member of any class. That would mean the layout of an instance of A would be:

    A's vtable;
    int a;
    

    And an instance of B would be:

    A's vtable;
    int a;
    B's vtable;
    int b;
    

    And you could generate correct virtual dispatching code from this layout.

    You can also optimize the layout by combining vtable pointers of vtables that have the same layout or if one is a subset of the other. So in the above example, you could also layout B as:

    B's vtable;
    int a;
    int b;
    

    Because B's vtable is a superset of A's. B's vtable has entries for A::f and B::g, and A's vtable has entries for A::f.

    For completeness, this is how you would layout all the vtables we've seen so far:

    A's vtable: A::f
    B's vtable: A::f, B::g
    C's vtable: A::f, B::g, C::h
    D's vtable: A::f
    E's vtable: A::f, B::g
    

    And the actual entries would be:

    A's vtable: A::f
    B's vtable: B::f, B::g
    C's vtable: C::f, C::g, C::h
    D's vtable: D::f
    E's vtable: E::f, B::g
    

    For multiple inheritance, you do the same analysis:

    class A { virtual void f(); int a; };
    class B { virtual void g(); int b; };
    class C: public A, public B { virtual void f(); virtual void g(); int c; };
    

    And the resultant layouts would be:

    A: 
    A's vtable;
    int a;
    
    B:
    B's vtable;
    int b;
    
    C:
    C's A vtable;
    int a;
    C's B vtable;
    int b;
    int c;
    

    You need a pointer to a vtable compatible with A and a pointer to a vtable compatible with B because a reference to C can be converted to a reference of A or B and you need to dispatch virtual functions to C.

    From this you can see that the number of vtable pointers a particular class has is at least the number of root classes it derives from (either directly or due to a superclass). A root class is a class that has a vtable that does not inherit from a class that also has a vtable.

    Virtual inheritance throws another bit of indirection into the mix, but you can use the same metric to determine the number of vtable pointers.

    0 讨论(0)
提交回复
热议问题