Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>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.</p> <p>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:</p> <pre><code>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; }; </code></pre> <p>As a result, you need five vtables: A, B, C, D, and E all need their own vtables.</p> <p>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.</p> <p>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:</p> <pre><code>A's vtable; int a; </code></pre> <p>And an instance of B would be:</p> <pre><code>A's vtable; int a; B's vtable; int b; </code></pre> <p>And you could generate correct virtual dispatching code from this layout.</p> <p>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:</p> <pre><code>B's vtable; int a; int b; </code></pre> <p>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.</p> <p>For completeness, this is how you would layout all the vtables we've seen so far:</p> <pre><code>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 </code></pre> <p>And the actual entries would be:</p> <pre><code>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 </code></pre> <p>For multiple inheritance, you do the same analysis:</p> <pre><code>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; }; </code></pre> <p>And the resultant layouts would be:</p> <pre><code>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; </code></pre> <p>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.</p> <p>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.</p> <p>Virtual inheritance throws another bit of indirection into the mix, but you can use the same metric to determine the number of vtable pointers.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload