K
K
Kirill H2017-08-31 09:50:30
C++ / C#
Kirill H, 2017-08-31 09:50:30

How do virtual function table pointers work?

TL;DR
I decided to study the arrangement of virtual function tables, because I heard that this can be asked at the interview.
Naturally began to experiment with class size for interest. By itself, there was a tricky example, which gave rise to my question.
I note right away that I compile only with GCC and try to adhere to the standard. I generally understand how memory is managed when creating/deleting class objects. But I didn’t find a word in the standard about how the table of virtual functions is created in this case.
Description of the problem
We have an empty class. According to the c++ standard, the size of its objects will be equal to the minimum addressable unit - 1 byte.
After adding the virtual function, the size of the object will already be equal to 4 bytes - the size of the pointer to the table of virtual functions.

Example #1
class A
{
    //sizeof(BaseA) = 1 byte
}

class B
{
    virtual void foo() {...}
    //sizeof(B) = 4 byte
}


Now we complicate the example and add two more classes, each with a virtual function, and then we inherit from them with an empty class. We get this:
Example #2
class BaseA
{
    virtual void foo()
    {

    }
};

class BaseB
{
    virtual void foo()
    {

    }
};

class Derived : BaseA, BaseB
{

};


How long will an object of class Derived take? So far, it is obvious that this will be a 4byte pointer to the BaseA class TVF + 4byte BaseB TVF pointer, and that's it: This is where the most interesting thing begins, how much memory will an object of the Derived class with its own virtual function take up?
sizeof(Derived) = 8
Example #3
#include <iostream>
using namespace std;

class BaseA
{
    virtual void foo()
    {

    }
};

class BaseB
{
    virtual void foo()
    {

    }
};

class DerivedWithVirtual : BaseA, BaseB
{
    virtual void bar()
    {

    }
};

class DerivedWithoutVirtual : BaseA, BaseB
{

};

int main()
{
    cout << "Size of Base class A: "
         << sizeof(BaseA) << endl;

    cout << "Size of Base class B: "
         << sizeof(BaseB) << endl;

    cout << "Size of derived class with virtual function: "
         << sizeof(DerivedWithVirtual) << endl;

    cout << "Size of derived class without virtual function: "
         << sizeof(DerivedWithoutVirtual) << endl;

    system("pause");

    return 0;
}


Here is what it will output:
Example output #3
Size of Base class A: 4
Size of Base class B: 4
Size of derived class with virtual function: 8
Size of derived class without virtual function: 8

The question itself
Why don't objects of the DerivedWithVirtual class have a pointer to their virtual function table and where is the pointer to the DerivedWithVirtual::bar function written?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
M
MiiNiPaa, 2017-08-31
@KirillHelm

I try to adhere to the standard, but in 11 I did not find a word about how the table of virtual functions is created in such cases
From the point of view of the standard, the table of virtual functions does not exist, but the function is chosen by magic.
Now about the question. Look at a simpler example:
struct base
{
    virtual void foo() {}
};

struct derived: base
{
    virtual void bar() {}
};

std::cout << sizeof(base) << '\n'
           << sizeof(derived) << '\n'
(representing a 32-bit machine and 4-byte pointers)
4
4

That is, when inheriting, in the general case, there are no additional pointers to the table of virtual functions (and this is good, it’s scary to imagine what would happen after a dozen inheritances). Where is the pointer to bar stored?
The answer is simple: it is added to a single table of virtual functions, immediately after the base class function pointers.
Extrapolating to your problem, the answer is obvious: the function is added to one of the tables created to work with the functions of the ancestors. Most likely the very first one.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question