Search code examples
c++inheritancememory-managementvirtualmultiple-inheritance

Memory usage by virtual inheritance


I have some classes (most of them are abstract, with virtual inheritance):

class A{
    public:
        virtual void f1() = 0;
        virtual void f2() = 0;
};

class B : virtual public A{
    public:
        virtual void f3() = 0;
};

class MyA : virtual public A{
    public:
        virtual void f1(){ ... }
        virtual void f2(){ ... }
};

class MyB : virtual public B, virtual public MyA{
    public:
        void f3(){ ... }
};

Now I use them:

B * object = new MyB();
object->f1(); //declared in A, imp. in MyA
object->f3(); //declared in B, imp. in MyB

Everything works fine, and the code is "good" for me (I can fast switch from MyB to YourB with changes in 1 line only).

But my question is:

How much additional memory it uses, compared to the similar code listed below (same result, different structure)?

I'm not good with memory layouts/vTables, so please explain it to me in a simple way - I want to know, if my application will spend more resources (memory) and if the executable will be slower?

And I compare that code to that one:

class MyA{
    public:
        virtual void f1(){ ... }
        virtual void f2(){ ... }
};

class MyB : public MyA{
    public:
        void f3(){ ... }
};

MyB * object = new MyB();
object->f1(); //declared in MyA, imp. in MyA
object->f3(); //declared in MyB, imp. in MyB

The sizeof(object) returns 4 in both examples (Win x32, Visual Studio native compiler), but I'm not sure if it's authoritative here. Maybe it doesn't count something - I don't think that both samples are 100% equal.


Solution

  • It depends on the implementation, but typically virtual inheritance will need:

    • an extra pointer (or offset) for each virtual base class: the adjustment to convert (for example) B* to A* will depend on which other subobjects in the same object also derive virtually from A. I think this can be stored in the vtable, rather than the object itself, so that the overhead could be per-class rather than per-object.
    • extra logic in the constructor and destructor, to determine whether or not the virtual base object needs initialising/destroying at that point.
    • extra work for some pointer conversions, reading the stored pointer/offset rather than applying a compile-time constant.

    For memory usage, you can measure the per-object overhead in your implementation by printing sizeof (MyB). Any per-class overhead will probably be negligible, unless you have a huge number of classes.