What is the best way to call virtual functions in a derived class so that the compiler can inline or otherwise optimize the call?
Example:
class Base {
virtual void foo() = 0;
};
class Derived: public Base {
virtual void foo() {...}
void bar() {
foo();
}
};
I want the call to foo()
in bar()
to always call Derived::foo()
.
It is my understanding that the call will result in a vtable lookup and the compiler cannot optimize it out since there may be another class inheriting from Derived.
I could explicitly call Derived::foo()
but that gets verbose if there are many virtual function calls in Derived. I also find it surprising that I could not find much material online addressing what seems to me to be a common case (a 'final' derived class calling virtual methods) so I wonder if I am misusing virtual functions here or excessively optimizing.
How should this be done? Stop prematurely optimizing and stick with foo()
, suck it up and use Derived::foo()
, or is there a better way?
C++11 contains the final
keyword, which "specifies that a virtual function can not be overridden in a derived class or that a class cannot be inherited from."1.
It appears that g++ is able to optimize the virtual function call in the derived class if it has been declared final
.
I created the following test:
virtualFunctions.h
#pragma once
class Base {
public:
virtual void foo();
virtual void bar();
virtual void baz();
int fooVar, barVar, bazVar;
};
class Derived: public Base {
public:
void test();
virtual void foo();
virtual void bar();
virtual void baz() final;
};
virtualFunctions.cpp
:
#include "virtualFunctions.h"
void Derived::test() {
foo();
Derived::bar();
baz();
}
void Derived::foo() {
fooVar = 101;
}
void Derived::bar() {
barVar = 202;
}
void Derived::baz() {
bazVar = 303;
}
I am using g++ 4.7.2 and with -O1 the generated assembly contains:
_ZN7Derived4testEv:
.LFB0:
.loc 1 3 0
.cfi_startproc
.LVL3:
pushl %ebx
.LCFI0:
.cfi_def_cfa_offset 8
.cfi_offset 3, -8
subl $24, %esp
.LCFI1:
.cfi_def_cfa_offset 32
movl 32(%esp), %ebx ; Load vtable from the stack
.loc 1 4 0
movl (%ebx), %eax ; Load function pointer from vtable
movl %ebx, (%esp)
call *(%eax) ; Call the function pointer
.LVL4:
.loc 1 5 0
movl %ebx, (%esp)
call _ZN7Derived3barEv ; Direct call to Derived::bar()
.LVL5:
.loc 1 6 0
movl %ebx, (%esp)
call _ZN7Derived3bazEv ; Devirtualized call to Derived::baz()
Derived::bar()
and Derived::baz()
were both called directly, while the vtable was used for foo()
.
The compiler may be able to optimize it and perform devirtualization if it can statically find out what type is used.
Virtual method calls are quite cheap. Sometime ago I read an article stating that the overhead is roughly ten percent compared to a normal method call. This of course does not consider the missing inlining opportunity.
I also have a feeling that this mixes interface and implementation. I think it would be better to split it into a pure interface and an implementation class.
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