Where in Memory Is Vtable Stored

Where in memory is vtable stored?

Depends on compiler.

In VC++, the vtable pointer stored at the beginning of the object allocation, before any member data. (Provided your class has at least one virtual member function.)

There also may be multiple vtable pointers, if your class multiply-inherits from other classes with vtables.

The vtables themselves are statically allocated somewhere in your address space.

Then the object layout looks like (for an instance of C):

A's VTable ptr
A's member variables.
B's Vtable ptr
B's member variables.
C's member variables.

for the heirarchy

class A {
virtual Ax() {}
int a, b;
};
class B {
virtual Bx() {}
int c, d;
};
class C : public A, public B {
int foo, bar;
};

virtual table and _vptr storage scheme

The first point to keep in mind is a disclaimer: none of this is actually guaranteed by the standard. The standard says what the code needs to look like and how it should work, but doesn't actually specify exactly how the compiler needs to make that happen.

That said, essentially all C++ compilers work quite similarly in this respect.

So, let's start with non-virtual functions. They come in two classes: static and non-static.

The simpler of the two are static member functions. A static member function is almost like a global function that's a friend of the class, except that it also needs the class`s name as a prefix to the function name.

Non-static member functions are a little more complex. They're still normal functions that are called directly--but they're passed a hidden pointer to the instance of the object on which they were called. Inside the function, you can use the keyword this to refer to that instance data. So, when you call something like a.func(b);, the code that's generated is pretty similar to code you'd get for func(a, b);

Now let's consider virtual functions. Here's where we get into vtables and vtable pointers. We have enough indirection going on that it's probably best to draw some diagrams to see how it's all laid out. Here's pretty much the simplest case: one instance of one class with two virtual functions:

Sample Image

So, the object contains its data and a pointer to the vtable. The vtable contains a pointer to each virtual function defined by that class. It may not be immediately apparent, however, why we need so much indirection. To understand that, let's look at the next (ever so slightly) more complex case: two instances of that class:

Sample Image

Note how each instance of the class has its own data, but they both share the same vtable and the same code--and if we had more instances, they'd still all share the one vtable among all the instances of the same class.

Now, let's consider derivation/inheritance. As an example, let's rename our existing class to "Base", and add a derived class. Since I'm feeling imaginative, I'll name it "Derived". As above, the base class defines two virtual functions. The derived class overrides one (but not the other) of those:

Sample Image

Of course, we can combine the two, having multiple instances of each of the base and/or derived class:

Sample Image

Now let's delve into that in a little more detail. The interesting thing about derivation is that we can pass a pointer/reference to an object of the derived class to a function written to receive a pointer/reference to the base class, and it still works--but if you invoke a virtual function, you get the version for the actual class, not the base class. So, how does that work? How can we treat an instance of the derived class as if it were an instance of the base class, and still have it work? To do it, each derived object has a "base class subobject". For example, lets consider code like this:

struct simple_base { 
int a;
};

struct simple_derived : public simple_base {
int b;
};

In this case, when you create an instance of simple_derived, you get an object containing two ints: a and b. The a (base class part) is at the beginning of the object in memory, and the b (derived class part) follows that. So, if you pass the address of the object to a function expecting an instance of the base class, it uses on the part(s) that exist in the base class, which the compiler places at the same offsets in the object as they'd be in an object of the base class, so the function can manipulate them without even knowing that it's dealing with an object of the derived class. Likewise, if you invoke a virtual function all it needs to know is the location of the vtable pointer. As far as it cares, something like Base::func1 basically just means it follows the vtable pointer, then uses a pointer to a function at some specified offset from there (e.g., the fourth function pointer).

At least for now, I'm going to ignore multiple inheritance. It adds quite a bit of complexity to the picture (especially when virtual inheritance gets involved) and you haven't mentioned it at all, so I doubt you really care.

As to accessing any of this, or using in any way other than simply calling virtual functions: you may be able to come up with something for a specific compiler--but don't expect it to be portable at all. Although things like debuggers often need to look at such stuff, the code involved tends to be quite fragile and compiler-specific.

Why is vptr stored as the first entry in the memory of a class with virtual functions?

It's an implementation detail but indeed many implementations do this.

It's rather efficient and convenient. Suppose you need to call a virtual function for a given object. You have a pointer to that object and the virtual function index. You need to somehow find which function should be called with that index and for this object. Okay, you simply access the first sizeof(void*) bytes behind the pointer and find where the vtable resides, then access the necessary element of vtable to fetch the function address.

You could store a separate map of "vtable for each object" or something but if you decide that you want to store the vptr inside the object then it's only logical to use the first bytes, not the last bytes or any other place because with this approach you know where to find the vptr once you have a pointer to the object, no extra data required.

Virtual tables memory location

First of all, Derived2 is of another type than Base1, so it needs some other information apart from the virtual functions table. Second, at least Derived2's destructor is another function than the one from Base1, so even if there were only the virtual functions in the table, that entry has to be differnt.
I am not sure about how MSVC implements RTTI on polymorphic types, but there has to be some identifcation of the type different to virtual functions, e.g. to enable dynamic_casts. So that first entry could very well be the pointer to the RTTI. I have no MSVC around at the moment, but you could try this:

struct Base {
virtual void foo() {};
virtual void bar() {};
virtual ~Base();
};

struct Derived {
virtual void foo() {};
virtual ~Derived();
};

int main() {
Base* b1 = new Base;
Base* b2 = new Derived;
};

Now inspect the first four or five elements of the __vfptr's of the two created objects, my guess is you will see one entry that is the same - it's the pointer to Base::bar. The others (Pointers to RTTI, foo and destructor) should be different.

Here comes some gueswork: Maybe you can see a different region in memory the pointers point to, since the RTTI pointers might point to the data segment, while the virtual function pointers point to code segment.

Update: there need not be an entry for RTTI in the vtable itself - it might be possible that some compilers implement RTTI just by comparing the addresses of the vtables.

Virtual Table layout in memory?

As others have said, this is compiler dependant, and not something that you ever really need to think about in day-to-day use of C++. However, if you are simply curious about the issue, you should read Stan Lippman's book Inside the C++ Object Model.

where is the overridden virtual method saved in the vtable c++ in multiple inheritance

An object d of Class D will have only a pointer to the VMT of class D, which will contain a pointer to D::f.
Since B1:f and B2::f can be called only statically from the scope of D class, there is no need for object d to keep a dynamic pointer to those overridden methods.

This of cause is not defined in the standard, this is just the usual/logical implementation of the compiler.

In fact the picture is more complicated, since the VMT of class D incorporates the VMTs of classes B1 and B2. But anyway, there is no need to dynamically call B1::f until an object of class B1 is created.



Related Topics



Leave a reply



Submit