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()
.