I had referred this question (I changed its title). I am aware that code generation related to virtual
ness are implementation specific. However, earlier question suggests that, there is an additional cost related to virtual
inheritance, when calling non-virtual base method.
I wrote following test codes and checked its assembly in g++ (with -O4
):
Common part
struct Base {
int t_size;
Base (int i) : t_size(i) {}
virtual ~Base () {}
int size () const { return t_size; };
};
struct D1 : virtual Base {
int a[10];
D1 () : Base(0) {}
~D1 () {}
};
struct D2 : virtual Base {
int a[20];
D2() : Base(0) {}
~D2 () {}
};
...
void foo (Base *p)
{
if(p->size())
return;
p = 0;
}
int main ()
{
Derived d;
foo(&d);
}
Now the difference part is here:
Code 1 (normal inheritance)
struct Derived : Base {
Derived () : Base(0) {}
~Derived () {}
int a[100];
};
Code 2 (virtual inheritance)
struct Derived : virtual Base {
Derived () : Base(0) {}
~Derived () {}
int a[100];
};
Code 3 (multiple virtual inheritance)
struct Derived : D1, D2 {
Derived () : Base(0) {}
~Derived () {}
int a[100];
};
When I checked its assembly, there is no difference between all 3 versions. And following is the assembly code:
.file "virtualInheritFunctionCall.cpp"
.text
.p2align 4,,15
.globl _Z3fooP4Base
.type _Z3fooP4Base, @function
_Z3fooP4Base:
.LFB1:
.cfi_startproc
rep
ret
.cfi_endproc
.LFE1:
.size _Z3fooP4Base, .-_Z3fooP4Base
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB2:
.cfi_startproc
xorl %eax, %eax
ret
.cfi_endproc
.LFE2:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
.section .note.GNU-stack,"",@progbits
Does it mean that virtual
inheritance doesn't have any extra cost, when certain optimization is ON ? Do I need to perform any more complex test code to evaluate this ? Note that, without optimization, there is a difference between these assemblies.
First, take a look at
foo
:Since
Base::size()
is non virtual, there is no virtual dispatch overhead withp->size()
.Next, look at how you invoke
foo
:Here, you are taking the address of an instance whose type is known statically, i.e., given an instance of
Derived
, the compiler can statically determine how to convert that to aBase *
. So, no matter howDerived
inherits fromBase
, the compiler knows how to convert it.You need an example with less type information available statically to measure the impact of virtual inheritance.
Obviously, it will adjust
this
or class pointer then pass it to original method.You might be able to observe overhead if you adjust 3rd example this way:
Also, once there are some member variables, you might want to investigate layout of resulting Derived class in debugger.
Inheritance (virtual or not) might add a little difference in a sense that compiler might decide adjust pointer to class when converting it from Derived* to Base* (or
this
if base non-virtual method is called from derived method) or vfptr. This will result in adding some value to current value ofthis
or pointer before passing it to function/method.However, this most likely will be done at the point when function call is invoked and it most likely will occur only when multiple inheritance is involved (because there might be more than one virtual method table). I.e. if you make class
C
that inherits classesA
andB
and they all have virtual methods, but no common ancestors, then when you call method that belongs toA
fromC
you might see pointer adjustments in disassembly. But that's it. the cost of such overhead will be ridiculously small.Please note that this is compiler-specific question, and everything i've written here is based on observation of microsoft compiler. I.e. it is "undocumented feature", as a result, if you worry about performance, you should use profiler instead of trying to guess performance impact. Main priority should be code readability anyway.