Reputation: 60381
The virtuality can have a double overhead :
Because of the memory overhead, I use some CRTP techniques to have a kind of static virtuality, when I need very high memory optimization.
But I wonder about the cost of virtuality for the runtime speed for non-virtual members :
#include <iostream>
class Base
{
public:
Base() {;}
virtual ~Base() {;}
public:
virtual void f1() {std::cout<<"f1 : Base"<<std::endl; /* FUNCTION BODY */}
void f2() {std::cout<<"f2 : Base"<<std::endl; /* FUNCTION BODY */}
void f3() {f1();}
};
class Derived : public Base
{
public:
Derived() {;}
virtual ~Derived() {;}
public:
virtual void f1() {std::cout<<"f1 : Derived"<<std::endl; /* FUNCTION BODY */}
};
And the main :
int main()
{
Base b;
Derived d;
Base* ptr = new Derived();
std::cout<<std::endl;
b.f1(); // 1a
b.f2(); // 1b
b.f3(); // 1c
std::cout<<std::endl;
d.f1(); // 2a
d.f2(); // 2b
d.f3(); // 2c
std::cout<<std::endl;
ptr->f1(); // 3a
ptr->f2(); // 3b
ptr->f3(); // 3c
std::cout<<std::endl;
return 0;
}
For each case : 1a, 1b ... 3c, where do I have a runtime overhead (increase of execution time) due to inheritance+virtuality compared to the case where Base and Derived are two completely independant classes with no inheritance ?
And particularly, is there any runtime overhead for the f2 function ?
Note : std::cout
is just an example. /* FUNCTION BODY */
can be 1k lines of code...
Upvotes: 2
Views: 243
Reputation: 13089
Why not just time it? It's an entirely trivial exercise..
First, some results
100 million instances of b.f1() = 0.774852 secs.
100 million instances of b.f2() = 0.78162 secs.
100 million instances of b.f3() = 1.85278 secs.
100 million instances of d.f1() = 0.773115 secs.
100 million instances of d.f2() = 0.886528 secs.
100 million instances of d.f3() = 1.88562 secs.
100 million instances of ptr->f1() = 1.02043 secs.
100 million instances of ptr->f2() = 0.778072 secs.
100 million instances of ptr->f3() = 1.72503 secs.
Assuming win32, (QueryPerformanceXXXXX & LARGE_INTEGER) you could use the following:
#include <windows.h>
#include <iostream>
using namespace std;
class Base
{
public:
Base() {;}
virtual ~Base() {;}
public:
virtual void f1() {};//std::cout<<"f1 : Base"<<std::endl; /* FUNCTION BODY */}
void f2() {}; //std::cout<<"f2 : Base"<<std::endl; /* FUNCTION BODY */}
void f3() {f1();}
};
class Derived : public Base
{
public:
Derived() {;}
virtual ~Derived() {;}
public:
virtual void f1() {};//std::cout<<"f1 : Derived"<<std::endl; /* FUNCTION BODY */}
};
LARGE_INTEGER clockFreq;
LARGE_INTEGER getTicks()
{
LARGE_INTEGER result;
QueryPerformanceCounter(&result);
return result;
}
double elapsedSecs(LARGE_INTEGER tStart, LARGE_INTEGER tEnd)
{
long ticksElapsed = tEnd.QuadPart - tStart.QuadPart;
double timePeriod = (double)ticksElapsed / (double)clockFreq.QuadPart;
return timePeriod;
}
int main()
{
LARGE_INTEGER tStart, tEnd;
Base b;
Derived d;
long i, max=100000000;
Base* ptr = new Derived();
// find how fast the clock ticks
QueryPerformanceFrequency(&clockFreq);
/*====================================================================================================
Test for access using b
b.f1()
b.f2()
b.f3()
====================================================================================================*/
std::cout<<std::endl;
tStart = getTicks();
for (i=0; i<max; i++)
{
b.f1(); // 1a
}
tEnd = getTicks();
double elapsed = elapsedSecs(tStart, tEnd);
cout << "100 million instances of b.f1() = " << elapsed << " secs." << endl;
std::cout<<std::endl;
tStart = getTicks();
for (i=0; i<max; i++)
{
b.f2(); // 1a
}
tEnd = getTicks();
elapsed = elapsedSecs(tStart, tEnd);
cout << "100 million instances of b.f2() = " << elapsed << " secs." << endl;
std::cout<<std::endl;
tStart = getTicks();
for (i=0; i<max; i++)
{
b.f3(); // 1a
}
tEnd = getTicks();
elapsed = elapsedSecs(tStart, tEnd);
cout << "100 million instances of b.f3() = " << elapsed << " secs." << endl;
/*====================================================================================================
Test for access using d
d.f1()
d.f2()
d.f3()
====================================================================================================*/
std::cout<<std::endl;
tStart = getTicks();
for (i=0; i<max; i++)
{
d.f1(); // 1a
}
tEnd = getTicks();
elapsed = elapsedSecs(tStart, tEnd);
cout << "100 million instances of d.f1() = " << elapsed << " secs." << endl;
std::cout<<std::endl;
tStart = getTicks();
for (i=0; i<max; i++)
{
d.f2(); // 1a
}
tEnd = getTicks();
elapsed = elapsedSecs(tStart, tEnd);
cout << "100 million instances of d.f2() = " << elapsed << " secs." << endl;
std::cout<<std::endl;
tStart = getTicks();
for (i=0; i<max; i++)
{
d.f3(); // 1a
}
tEnd = getTicks();
elapsed = elapsedSecs(tStart, tEnd);
cout << "100 million instances of d.f3() = " << elapsed << " secs." << endl;
/*====================================================================================================
Test for access using ptr
ptr->f1()
ptr->f2()
ptr->f3()
====================================================================================================*/
std::cout<<std::endl;
tStart = getTicks();
for (i=0; i<max; i++)
{
ptr->f1(); // 1a
}
tEnd = getTicks();
elapsed = elapsedSecs(tStart, tEnd);
cout << "100 million instances of ptr->f1() = " << elapsed << " secs." << endl;
std::cout<<std::endl;
tStart = getTicks();
for (i=0; i<max; i++)
{
ptr->f2(); // 1a
}
tEnd = getTicks();
elapsed = elapsedSecs(tStart, tEnd);
cout << "100 million instances of ptr->f2() = " << elapsed << " secs." << endl;
std::cout<<std::endl;
tStart = getTicks();
for (i=0; i<max; i++)
{
ptr->f3(); // 1a
}
tEnd = getTicks();
elapsed = elapsedSecs(tStart, tEnd);
cout << "100 million instances of ptr->f3() = " << elapsed << " secs." << endl;
return 0;
}
Upvotes: 4