How many vptr will a object of class(uses single/multiple inheritance) have?

China☆狼群 提交于 2019-11-29 10:35:42

问题


How many vptrs are usually needed for a object whose clas( child ) has single inheritance with a base class which multiple inherits base1 and base2. What is the strategy for identifying how many vptrs a object has provided it has couple of single inheritance and multiple inheritance. Though standard doesn't specify about vptrs but I just want to know how an implementation does virtual function implementation.


回答1:


Why do you care? The simple answer is enough, but I guess you want something more complete.

This is not part of the standard, so any implementation is free to do as they wish, but a general rule of thumb is that in an implementation that uses virtual table pointers, as a zeroth approximation, for the dynamic dispatch you need at most as many pointers to virtual tables as there are classes that add a new virtual method to the hierarchy. (In some cases the virtual table can be extended, and the base and derived types share a single vptr)

// some examples:
struct a { void foo(); };           // no need for virtual table
struct b : a { virtual foo1(); };   // need vtable, and vptr
struct c : b { void bar(); };       // no extra virtual table, 1 vptr (b) suffices
struct d : b { virtual bar(); };    // extra vtable, need b.vptr and d.vptr

struct e : d, b {};                 // 3 vptr, 2 for the d subobject and one for
                                    // the additional b
struct f : virtual b {};
struct g : virtual b {};
struct h : f, g {};                 // single vptr, only b needs vtable and
                                    // there is a single b

Basically each subobject of a type that requires its own dynamic dispatch (cannot directly reuse the parents) would need its own virtual table and vptr.

In reality compilers merge different vtables into a single vtable. When d adds a new virtual function over the set of functions in b, the compiler will merge the potential two tables into a single one by appending the new slots to the end of the vtable, so the vtable for d will be a extended version of the vtable for b with extra elements at the end maintaining binary compatibility (i.e. the d vtable can be interpreted as a b vtable to access the methods available in b), and the d object will have a single vptr.

In the case of multiple inheritance things become a bit more complicated as each base needs to have the same layout as a subobject of the complete object than if it was a separate object, so there will be extra vptrs pointing to different regions in the complete object's vtable.

Finally in the case of virtual inheritance things become even more complicated, and there might be multiple vtables for the same complete object with the vptr's being updated as construction/destruction evolves (vptr's are always updated as construction/destruction evolves, but without virtual inheritance the vptr will point to the base's vtables, while in the case of virtual inheritance there will be multiple vtables for the same type)




回答2:


The fine print

Anything regarding vptr/vtable is not specified, so this is going to be compiler dependent for the fine details, but the simple cases are handled the same by almost every modern compiler (I write "almost" just in case).

You have been warned.

Object layout: non-virtual inheritance

If you inherit from base classes, and they have a vptr, you naturally have as many inherited vptr in your class.

The question is: When will the compiler add a vptr to a class that already has an inherited vptr?

The compiler will try to avoid adding redundant vptr:

struct B { 
    virtual ~B(); 
};

struct D : B { 
    virtual void foo(); 
};

Here B has a vptr, so D does not get its own vptr, it reuses the existing vptr; the vtable of B is extended with an entry for foo(). The vtable for D is "derived" from the vtable for B, pseudo-code:

struct B_vtable { 
    typeinfo *info; // for typeid, dynamic_cast
    void (*destructor)(B*); 
};

struct D_vtable : B_vtable { 
    void (*foo)(D*); 
};

The fine print, again: this is a simplification of a real vtable, to get the idea.

Virtual inheritance

For non virtual single inheritance, there is almost no room for variation between implementations. For virtual inheritance, there are a lot more variations between compilers.

struct B2 : virtual A {
};

There is a conversion from B2* to A*, so a B2 object must provide this functionality:

  • either with a A* member
  • either with an int member: offset_of_A_from_B2
  • either using its vptr, by storing offset_of_A_from_B2 in the vtable

In general, a class will not reuse the vptr of its virtual base class (but it can in a very special case).



来源:https://stackoverflow.com/questions/3342035/how-many-vptr-will-a-object-of-classuses-single-multiple-inheritance-have

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!