Search code examples
c++inheritancelanguage-designvtable

Why are C++ inheritance mechanisms opaque?


Why, for example, is there no language support to examine a vtable? Why can't I replace a member function with a new one? I have a gut feeling that there are ways to put such features to good use.

Are there any other languages out there which allow me to do such things?


Solution

  • The main reason is that keeping vtable as an implementation detail allows any concrete implementation to optimize it as it sees fit; this means that it can e.g. trim or even eliminate vtable altogether if it can prove that there are no virtual calls for a given method (or all methods). Or it may replace a vtable dispatch with an if-else type check if e.g. it sees that there are only a few alternatives (this can be advantageous because branch prediction will work in this case, but not with vtables, and also because if-else branches can then be inlined). It can reorder methods in vtable such that most commonly called ones come earlier, or such that those that are commonly called one right after another fill adjacent slots in vtable to take advantage of caching. And so on, and so forth. Of course, all those implementations would also make vtable layout entirely unpredictable, and thus useless, if it were to be exposed (by the language spec) to implementation.

    As well, vtables aren't as simple as they sound to be. For example, compilers often have to generate thunks to fix-up this pointer for things such virtual inheritance, or multiple inheritance combined with covariant return types. This is again something that doesn't have a "single best way" to do it (which is why different compilers do it differently), and standardizing it would effectively require settling on a particular way.

    That said, "vtable switching" is a potentially useful technique if exposed as a higher-level construct (so that optimizations are still possible). For an example, see UnrealScript, which allows one to define several states for a class (one default, other named), and override some methods in named states. Derived classes can override more methods in existing states, or add their own states and override in them. Furthermore, states can extend other states (so if a method isn't overridden for a particular state, it falls back to the "parent" state, and so on until the chain reaches the default state). For actor modelling (which games essentially are) this all makes a lot of sense, which is why UnrealScript has it. And the obvious efficient implementation mechanism for all of this is vtable switching, with each state having a separate vtable.