What you say is true, but it's mitigated in a few ways:
- None of this matters if the actual class of the object is known. It only matters if you're
accessing a derived class via a base class pointer.
- If you're accessing several virtual members, the dereference to get the virtual function
table only needs to be done once.
- Virtual methods are rare in C++ (compared to e.g. Java). I don't believe there are any at
all in the standard library, for example.
- Using less memory per object will improve your cache hit rate when you have more than a few
objects.
Here's a C++ benchmark. "----" indicates a new file, to prevent too much being optimised
away:
struct base {
virtual void foo() = 0;
};
struct derived: public base {
void foo() {
f1();
}
};
----
int main()
{
for (int i=0; i<100000000; ++i) {
base* p = f2();
p->foo();
}
}
----
void f1() {
}
base* f2() {
static derived d;
return &d;
}
And here's a C version (well, actually it's still C++ but it's using a function pointer in the
struct rather than a virtual function):
struct base {
typedef void(*foo_t)();
const foo_t foo;
base(foo_t f_): foo(f_) {}
};
----
int main() // same as C++ version
{
for (int i=0; i<100000000; ++i) {
base* p = f2();
p->foo();
}
}
----
void f1() {
}
struct derived: public base {
derived(): base(&f1) {}
};
base* f2() {
static derived d;
return &d;
}
Comparing these programs (x86, gcc 4.3.1, -O3) I find that the "C" version is about 20%
faster, or around 6 nanoseconds per call, on this 1 GHz VIA C3 machine. That fraction would
clearly drop if you actually did something inside the virtual function.
Posted Jun 26, 2008 12:45 UTC (Thu) by tbrownaw (guest, #45457)
[Link]
- Virtual methods are rare in C++ (compared to e.g. Java). I don't believe there are any at
all in the standard library, for example.
std::streambuf::xs{get,put}n and several other protected streambuf functions. Not something you'll usually work with directly, but used by all the i/o streams.