What happens when you add a first virtual function to a class in terms of its memory consumption, object layout, and so on? How much slower are virtual functions than normal functions?
Asked
Active
Viewed 119 times
5
-
2http://stackoverflow.com/questions/449827/virtual-functions-and-performance-c – Alan Stokes May 01 '16 at 22:13
-
2http://stackoverflow.com/questions/99297/how-are-virtual-functions-and-vtable-implemented – Alan Stokes May 01 '16 at 22:14
-
What an excellent suggestion you've made: to create a few simple programs that can be benchmarked to determine the overhead of virtual classes. Be sure to edit your question to include the results of your benchmarking. – Sam Varshavchik May 01 '16 at 22:14
-
Thanks for the links! I'm new to Stack Overflow. I tried searching the question but apparently didn't search hard enough! @AlanStokes – ltnewberry May 01 '16 at 22:16
-
1Long story short: the first virtual function adds a pointer to the vtable as an extra hidden member. On current processors, if you keep calling the same virtual function in a loop on objects of the same type there's essentially no performance penalty compared to a "regular" function call, since the branch predictor quickly picks up the pattern. The big performance impact of virtual functions is generally in the missed opportunity for inlining. – Matteo Italia May 01 '16 at 23:17
1 Answers
2
If you really care I suggest testing it on your own compiler & system, as it may produce different results. Here is an example I used:
#include <iostream>
template<typename B> struct Base { B b; void f() {}; };
template<typename B> struct Base_Virtual { B b; virtual void f() {}; };
template<typename B> struct Base_Pointer { B b; void* p; };
#define PRINT_ALIGNOF_SIZEOF(T) std::cout << "sizeof(" #T ") = " << sizeof(T) << ", alignof(" #T ") = " << alignof(T) << std::endl
int main()
{
PRINT_ALIGNOF_SIZEOF(char);
PRINT_ALIGNOF_SIZEOF(Base<char>);
PRINT_ALIGNOF_SIZEOF(Base_Virtual<char>);
PRINT_ALIGNOF_SIZEOF(Base_Pointer<char>);
std::cout << std::endl;
PRINT_ALIGNOF_SIZEOF(void*);
PRINT_ALIGNOF_SIZEOF(Base<void*>);
PRINT_ALIGNOF_SIZEOF(Base_Virtual<void*>);
PRINT_ALIGNOF_SIZEOF(Base_Pointer<void*>);
std::cin.ignore();
}
Which produced the following output (with Windows 10 / Visual C++ 14.0 compiled as an ‘x64’ program)
sizeof(char) = 1, alignof(char) = 1
sizeof(Base<char>) = 1, alignof(Base<char>) = 1
sizeof(Base_Virtual<char>) = 16, alignof(Base_Virtual<char>) = 8
sizeof(Base_Pointer<char>) = 16, alignof(Base_Pointer<char>) = 8
sizeof(void*) = 8, alignof(void*) = 8
sizeof(Base<void*>) = 8, alignof(Base<void*>) = 8
sizeof(Base_Virtual<void*>) = 16, alignof(Base_Virtual<void*>) = 8
sizeof(Base_Pointer<void*>) = 16, alignof(Base_Pointer<void*>) = 8
This suggests that adding a virtual function to a class is equivalent to adding a void*
member at the end. (Note: adding more virtual functions did not change the result).
As a general rule of thumb, only add virtual functions if they are useful (though adding a virtual destructor is considered best practice if your class is going to be used in hierarchies, even if it is always trivial).

Isaac
- 816
- 5
- 12