Introduction
This post will talk about MSVC internals for the not-so-talked case of Class Virtual Inheritance. This is something that added to multiple-inheritance can become a real problem if one stumbles upon it for the first time. There are multiple blogs and information out there talking about RTTI1, Multi-Class Inheritance and memory layouts for those cases2, but not so much about the singularities of this feature that’s essential to enable polymorphism. Or at least, not so in a digestible way.
Original Microsoft’s patents explaining the topic3 in detail exist since the 90’s, however the medium where they’re stored may not be the most didactic, making it a little “dry” to read each one (sorry Jan!). Still no blogs attempt to go into border-cases or how the compiler reasons about it. Documents from one of the original MSVC architect4, Jan Gray, talk about virtual inheritance but not so much as to explain all there is. Hope this post helps clarify the situation using Jan’s own patents from back in the day.
Virtual Inheritance
What is it?
Before starting, we must at least make an introduction about this topic. As we already know with inheritance in MSVC, all derived classes that inherit from a base class actually are contained in the underlying struct object that represents them. But what would happen in the case we have many base classes that already share a common ancestor? This leads to redundancy on the derived class (we have as many ancestor class copies as base classes that inherit it), and ambiguity when altering the state of the shared ancestor class (which copy of the ancestor must be changed?).
Virtual inheritance is MSVC answer to both the diamond problem and the redundancy problem that we described before. When using the reserved keyword virtual when inheriting from a class, this causes the compiler to only consider said class only once in any derived class that contains said base classes.
|
|
Take the previous example. If a new class D inherited from class C and also class A, there still would only be one class A inside class D struct definition.
Virtual Base Table
One would ask themselves why not use virtual inheritance everywhere it’s possible, since classes that share ancestors would be a fairly common use case. But as always, there are costs and benefits for a solution, and in this case it’s a trade-off between memory space conveniency and a penalty in execution speed.
Usually, classes have fixed offsets (and sizes) for their members and for the internal classes in regular multi-inheritance, however with virtual inheritance the sizes for the intermediate base classes, and the offsets to the virtually inherited classes will vary.
Think for a second about the class A, class B and class C example. Usually an instance of class C would contain both class A and class B inside, however if we add the following:
|
|
Then now the nested class C that lives inside class D wouldn’t contain class A anymore, but be contained inside class D and put at the end of it. And for class E, the same pattern would follow, where a smaller version of class C and class D are put before class A at the end.

Let’s call from now on a “virtually inherited class”/“virtual class” to classes that are like class A, a “virtually inheriting” to classes that are like class C, and “derived class” to classes that are like class D or class E.
If there are 2 different versions of
class Candclass D, how do we know the correct offsets toclass Ainsideclass Dandclass E?
A solution for this dynamic size (and offset) problem is the vbtable. This per-base-class structure holds as its first member the offset to reach the start of the virtually inheriting class, and in the next members it holds all the offsets (in left-to-right order when declaring inheritance) required to reach all of the virtual base classes for a derived class.
The required offsets for a vbtable are calculated by MSVC at compile-time, then it’s put at the .rdata segment of a program. Finally, a pointer to a class-specific vbtable is assigned to a class member at construction for an instance of a virtually inherited class. This vbtable pointer is usually held as either the first or second member inside a class: first if there is no vftable* for this class, and second when there is.
The vbtable for class D would look like the following.
|
|
This first offset being -8 happens because usually the first internal field for a class in MSVC holds the vftable pointer (which is only added if there’s at least one declared virtual method in the inheritance path), so to reach the start of the class one would have to “jump” 8 bytes (in a 64-bit processor) before the vbtable. In the case of a class not having a vftable (which means there’s no declared virtual method), the first offset would be 0 and the vbtable would be the first internal field for a class.
The second to Nth offsets will correspond to the number of bytes between the start of the vbtable and the different virtual base classes (in this case there’s only class A). At this point you may also have noticed that each class that contains a virtual base class will have it’s own vbtable, as these offsets are class-dependent.
Construction Displacement
But wait, knowing from before that there’s 2 possible sizes for the virtually inheriting class, wouldn’t there have to be 2 different
vbtablesfor a class that virtually inherits from another? (e.g.class C).
Yes, but there’ll be 2 vbtables only in the case the virtually inheriting class (class C) is also constructed somewhere in the code (thus class C couldn’t be an abstract class). Otherwise the compiler will omit the constructor along with its vbtable, and just have the vbtable for the derived class (class D).
Then how would the
vbtablessolve on their own these special cases?
That’s the neat part, they don’t!
And that’s how the construction displacement field comes to complement the vbtable.
This field is an internally managed class member that’s used by the compiler and set on construction for an instance of a virtually inherited class. The actual value corresponds to the difference between the offset to the virtually inherited class when a base class is inherited by a derived class, and the original offset to the virtually inherited class when this same base class is instanced by itself.
The previous description may sound very confusing at first, but take some time re-reading it after watching the next picture following the example classes used before.

Here, dVA2 is the first offset mentioned before, while dVA1 is the second offset. The construction displacement field for class D will be the difference between them (dVA2 - dVA1).
This last offset (dVA1) could become hardcoded (e.g. passed as an immediate to a register) by the compiler when calculating the construction displacement when that last class is abstract, and in that case its offset won’t live in the .rdata segment inside a vbtable like it does for any other class. We’ll also see later that this substraction to calculate the difference is performed explicitly on the constructor, so no “magic numbers” will appear here.
An interesting thing about the construction displacement is that this is an optional field that is added only when certain conditions1 are met. The actual criteria used is the following.
---
title: Add Construction Displacement?
---
flowchart TD
d2[Base class is virtually inherited?] -- N --> d0[No C. Displacement]
d2 -- Y --> d3[Construction displacement field already is in ancestor class?]
d3 -- Y --> d1[Add C. Displacement]
d3 -- N --> d4[Base class has virtual function member?]
d4 -- N --> d0
d4 -- Y --> d5[All constructors/destructors for underived class are compiler generated?]
d5 -- Y --> d0
d5 -- N --> d6[All public+protected constructors/destructors for the derived class are compiler generated?]
d6 -- Y --> d0
d6 -- N --> d7[Derived class has no friend classes?]
d7 -- Y --> d0
d7 -- N --> d8[Derived class is non-derivable?]
d8 -- Y --> d0
d8 -- N --> d9[All derived class' overridden virtual methods are pure?]
d9 -- Y --> d0
d9 -- N --> d1
This may look very border-case-ish and intrincated, however if you look closely, many of these conditions are achievable in most cases as a lot of them require “No” to continue down to the “Add C. Displacement” action in the decision tree.
We can thus attempt to summarize the criteria with: if a virtually inherited base class has at least one function member that is overridden by a derived class and at least one custom constructor/destructor in said derived class, it will have a construction displacement.
One last thing about the construction displacement field, is that it’s usually located 4 bytes behind the start of each inherited virtual base class that satisfies the previous criteria for a derived class.
Adjustors / Thunks
Ok, this
construction displacementfield does accurately get you the different sizes when a class is virtually inherited, but how is it used?
Good question! We managed to digest the previous definitions, but it only has meaning as long as it’s being used somewhere.
The construction displacement field is a cornerstone when understanding how polymorphism works without errors for virtual function member overriding. It’s focused on the special case when a derived class object is constructed, as we’ll see shortly.
Usually virtual function members that aren’t pure inside a class, can be called through the derived class and the compiler will add a simple adjustment of the this pointer using a fixed offset before calling it. Remember that on multiple-inheritance, offsets and sizes for a class are basically “static” or unchanging along the program.
However, when virtual function members that are defined somewhere on the virtual class become overridden by a derived class, these cannot be called directly and neither their offsets for the this pointer be hardcoded. We learned before that virtual inheriting classes can have 2 sizes. Then, for calling these new overridden methods, an adjustment is required for the this pointer passed to the virtual function member that still works regardless of the virtual inheriting class being smaller or larger than expected.
Worry not, as the construction displacement is exactly the difference required to adjust correctly the this pointer. If we would just substract this difference with the this pointer we would have it (this = this - (dVA2 - dVA1)). The function that performs this is called an adjustor or thunk.

The adjustor functions occupy the place in the vftable associated with the virtual class that originally “introduced” the function, but that lives inside the derived class (we’ll see it shortly after). The class that “introduces” a function member for the first time becomes the expected class for the this pointer passed to this function member, even for overriden function members for other classes.
Just as you heard, a derived class can have as many vftables as base classes it possess inside its struct definition (as long as these classes have at least one virtual function member). Each vftable is associated with a specific base class where their function members were introduced.
|
|
Then, the diagram for the layout of these classes would look like the next image. Note that the vftables contain pointers to functions, and some contain a direct jump to the original function member for a class, without any intermediate function in-between nor duplication of code.

The adjustor function for any function member looks something like the following.
|
|
Everything in Action
Now that we know the what’s and how’s of the construction displacement, we still need to know the when’s. Most of the time, the construction displacement value for a derived class is 0, unless in the case a derived class object is being constructed. This is the very unique use case for this internal field. Imagine the following scenario.
|
|
class C is overriding function member f1(), and calling its own version on its constructor to then call class A version for f2(). Then, as class D inherits both class C and class A, calls to the different constructors will be performed at different times. We already know from regular inheritance (single/multiple) that when a deriving class gets constructed, their base class constructors are nested and called just before the derived class one. This includes the assignment for the vftables and construction displacements too, although temporarily.
If we attempt to instance an object of class D, the compiler will end up creating the following code for its constructor.
|
|
As you may notice, there’s 2 different flag arguments. These are added by the compiler to handle the 2 different class sizes when a virtual inheriting class is also used as a base class or when it’s instanced by itself. In this case, class C gets instanced as a base class for class D, so the flag is hardcoded to 0 and class A won’t be initialized for class C. However for class D, this flag will be hardcoded to 1 wherever the instantiation of an object of this class is performed as it’s the final derived (and not inherited) class for this example.
The actual interesting part occurs inside the constructor for class C. First class B is initialized inside the nested version of class C, which just assigns the original vftable for class B. This is just temporary, as soon after the vftable for the nested version of class B inside class C will be assigned to the modified class C one (containing B::b1). Following it, the vftable for the nested class A will be assigned the vftable made for class C (containing C::adjustor_f1 and A::f2).
Continuing, a non-null construction displacement is calculated and assigned (dVA2 - dVA1), and then a call to C::adjustor_f1() and A::f2() are performed in order, using a displaced this pointer containing the start address where the nested class A for class D should be. This is done by adding dVA2 to the this+8 pointer (so it starts from the vbtable), which will make the adjustor function do the following substraction this = (this + 8 + dVA2) - (dVA2 - dVA1) => this = this + 8 + dVA1. This makes it possible for a virtual inheriting class (class C) with 2 sizes to reach the correct virtual class address (class A).
Finally, going back to class D constructor after returning from the class C constructor, their corresponding vftables are assigned (containing C::f1 and D::f2) and the construction displacement for class D is set to 0. This construction displacement field has far outlived its purpose, and now it won’t be used anywhere else on the program.
A final look at these classes after instantiaton of class D is the following.

Closing Remarks
Well, that’s all for this post before it becomes too long for anyone to read in one sit.
Next part will be about applying this knowledge into a real program, while reverse engineering it in IDA. We’ll explore how the constructors slowly but surely lay out the nested classes and the derived class, how would overridden methods look like, how does the program access a virtual member, and even some RTTI analysis for virtually derived class.
Theory is just as good as you use it. See you on the next part: Virtual Inheritance Case Study: Chimera.exe.
-
Lipski, L. (2021, June 6). RTTI Internals in MSVC. https://www.lukaszlipski.dev/post/rtti-msvc/ ↩︎ ↩︎
-
Skochinsky, I. (2006, Sept 21). Reversing Microsoft Visual C++ Part II: Classes, Methods and RTTI. https://www.openrce.org/articles/full_view/23 ↩︎
-
Jan Gray et al. (1994). Method for object construction in a compiler for an object-oriented programming language (U.S. Patent No. 5371891). U.S. Patent and Trademark Office. https://www.freepatentsonline.com/5371891.html ↩︎
-
Gray, J. (1994, March). C++: Under the Hood. https://www.openrce.org/articles/files/jangrayhood.pdf ↩︎