问题
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];
};
Overall code here.
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.
回答1:
Rather than performance, I want to know how the virtual inheritance deals with non-virtual base methods
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:
- Add virtual methods (non-overlapping names) to Base, D1 and D2. This will cause compiler to create virtual method tables.
- Add non-overlapping data fields/member variables (non-overlapping, different names) to Base, D1, D2 and derived.
- Add non-virtual method to D2 that operates on data fields in D2 and Base.
- Add non-virtual method to D1 that operates on data fields in D1 and Base.
- Add non-v\irtual method to Derived that calls aforementioned non-virtual methods in D2 and D1 then operates on data fields in D2, D1, Base and Derived.
- Investigate disassembly.
Also, once there are some member variables, you might want to investigate layout of resulting Derived class in debugger.
When I checked its assembly, there is no difference between all 3 versions
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 of this
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 classes A
and B
and they all have virtual methods, but no common ancestors, then when you call method that belongs to A
from C
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.
回答2:
First, take a look at foo
:
void foo (Base *p)
{
if(p->size())
return;
p = 0;
}
Since Base::size()
is non virtual, there is no virtual dispatch overhead with p->size()
.
Next, look at how you invoke foo
:
int main ()
{
Derived d;
foo(&d);
}
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 a Base *
. So, no matter how Derived
inherits from Base
, the compiler knows how to convert it.
You need an example with less type information available statically to measure the impact of virtual inheritance.
来源:https://stackoverflow.com/questions/9444003/is-there-any-extra-cost-of-calling-non-virtual-base-methods-in-virtual-inheritan