Does using virtual inheritance in C++ have a runtime penalty in compiled code, when we call a regular function member from its base class? Sample code:
class A { public: void foo(void) {} }; class B : virtual public A {}; class C : virtual public A {}; class D : public B, public C {}; // ... D bar; bar.foo ();
If you don't use virtual functions, you don't understand OOP yet. Because the virtual function is intimately bound with the concept of type, and type is at the core of object-oriented programming, there is no analog to the virtual function in a traditional procedural language.
The answer is definitely no. The base of an idiomatic answer can be the most fundamental idea of C++: you only pay for what you use. And if you don't need virtual inheritance, you should rather not pay for it. Virtual inheritance is almost never needed.
Virtual base classes offer a way to save space and avoid ambiguities in class hierarchies that use multiple inheritances. When a base class is specified as a virtual base, it can act as an indirect base more than once without duplication of its data members.
Virtual inheritance is a C++ technique that ensures only one copy of a base class's member variables are inherited by grandchild derived classes.
There may be, yes, if you call the member function via a pointer or reference and the compiler can't determine with absolute certainty what type of object that pointer or reference points or refers to. For example, consider:
void f(B* p) { p->foo(); } void g() { D bar; f(&bar); }
Assuming the call to f
is not inlined, the compiler needs to generate code to find the location of the A
virtual base class subobject in order to call foo
. Usually this lookup involves checking the vptr/vtable.
If the compiler knows the type of the object on which you are calling the function, though (as is the case in your example), there should be no overhead because the function call can be dispatched statically (at compile time). In your example, the dynamic type of bar
is known to be D
(it can't be anything else), so the offset of the virtual base class subobject A
can be computed at compile time.
Yes, virtual inheritance has a run-time performance overhead. This is because the compiler, for any pointer/reference to object, cannot find it's sub-objects at compile-time. In constrast, for single inheritance, each sub-object is located at a static offset of the original object. Consider:
class A { ... }; class B : public A { ... }
The memory layout of B looks a little like this:
| B's stuff | A's stuff |
In this case, the compiler knows where A is. However, now consider the case of MVI.
class A { ... }; class B : public virtual A { ... }; class C : public virtual A { ... }; class D : public C, public B { ... };
B's memory layout:
| B's stuff | A's stuff |
C's memory layout:
| C's stuff | A's stuff |
But wait! When D is instantiated, it doesn't look like that.
| D's stuff | B's stuff | C's stuff | A's stuff |
Now, if you have a B*, if it really points to a B, then A is right next to the B- but if it points to a D, then in order to obtain A* you really need to skip over the C sub-object, and since any given B*
could point to a B or a D dynamically at run-time, then you will need to alter the pointer dynamically. This, at the minimum, means that you will have to produce code to find that value by some means, as opposed to having the value baked-in at compile-time, which is what occurs for single inheritance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With