G
GianGuz
Everyone knows about the complex and cpu-expensive procedures taken by
dynamic_cast to find the right function call in a virtual classes
hierarchy.
The question I would to rise is when dynamic_cast is really necessary?
A wise usage of templates and/or non dynamic_cast operators can grant
the compiler with any information it needs to understand at compile
time what is the right method to call.
In the following example I tested the usage of dynamic_cast to call a
sibling method in a simple 4 class hierarchy. I compared it with a
version in wich static_cast is used from the topmost derived class to
pass information to
its super classes. Results were stunnig. Dynamic_cast version perform
at least 14 time slower than the static_cast one.
Let's see the code:
#include <string>
#include <iostream>
extern "C" {
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
}
#define INIT_TIMER long T; time(&T); srand(T);
#define START_TIMER long start0,end0; clock_t start1,end1;
time(&start0); start1 = clock();
#define END_TIMER time(&end0); end1 = clock();
#define PRINT_TIMER cout << "Computation time (sec)" << (end0) -
(start0) << endl; cout << "Computation time (msec)" << (end1) -
(start1) << endl;
#define MAX_VALUE 50000000
using namespace std;
class A;
class BASE {
public:
BASE() { }
virtual int a() = 0;
virtual int b(A* ptr = NULL) = 0;
virtual int c() = 0;
virtual int cS() = 0;
virtual ~BASE() { }
};
class A : virtual public BASE {
public:
A() { }
int a() { return 0; }
virtual ~A() { }
};
class B : virtual public BASE {
public:
B() { }
protected:
int b(A* ptr = NULL) {
if (ptr == NULL) return dynamic_cast<A*>(this)->a() + 1;
else return ptr->a() + 1;
}
virtual ~B() { }
};
class C : virtual public A, virtual public B {
public:
C() { }
int a() { return 2; }
int c() { return b(); }
int cS() { return b(static_cast<A*>(this)); }
~C() { }
};
int main() {
INIT_TIMER
{
cout << "static_cast version " << endl;
BASE* base = new C;
long result = 0;
START_TIMER
for(int i=0; i<MAX_VALUE; i++) {
result += base->cS();
}
END_TIMER
delete base;
cout << "Result " << result << endl;
PRINT_TIMER
}
{
cout << "dynamic_cast version " << endl;
BASE* base = new C;
long result = 0;
START_TIMER
for(int i=0; i<MAX_VALUE; i++) {
result += base->c();
}
END_TIMER
delete base;
cout << "Result " << result << endl;
PRINT_TIMER
}
}
I would like to know comments about that. I also would like to see an
example
in wich dynamic_cast cannot be absolutely removed.
Cheers.
Gianguglielmo
dynamic_cast to find the right function call in a virtual classes
hierarchy.
The question I would to rise is when dynamic_cast is really necessary?
A wise usage of templates and/or non dynamic_cast operators can grant
the compiler with any information it needs to understand at compile
time what is the right method to call.
In the following example I tested the usage of dynamic_cast to call a
sibling method in a simple 4 class hierarchy. I compared it with a
version in wich static_cast is used from the topmost derived class to
pass information to
its super classes. Results were stunnig. Dynamic_cast version perform
at least 14 time slower than the static_cast one.
Let's see the code:
#include <string>
#include <iostream>
extern "C" {
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
}
#define INIT_TIMER long T; time(&T); srand(T);
#define START_TIMER long start0,end0; clock_t start1,end1;
time(&start0); start1 = clock();
#define END_TIMER time(&end0); end1 = clock();
#define PRINT_TIMER cout << "Computation time (sec)" << (end0) -
(start0) << endl; cout << "Computation time (msec)" << (end1) -
(start1) << endl;
#define MAX_VALUE 50000000
using namespace std;
class A;
class BASE {
public:
BASE() { }
virtual int a() = 0;
virtual int b(A* ptr = NULL) = 0;
virtual int c() = 0;
virtual int cS() = 0;
virtual ~BASE() { }
};
class A : virtual public BASE {
public:
A() { }
int a() { return 0; }
virtual ~A() { }
};
class B : virtual public BASE {
public:
B() { }
protected:
int b(A* ptr = NULL) {
if (ptr == NULL) return dynamic_cast<A*>(this)->a() + 1;
else return ptr->a() + 1;
}
virtual ~B() { }
};
class C : virtual public A, virtual public B {
public:
C() { }
int a() { return 2; }
int c() { return b(); }
int cS() { return b(static_cast<A*>(this)); }
~C() { }
};
int main() {
INIT_TIMER
{
cout << "static_cast version " << endl;
BASE* base = new C;
long result = 0;
START_TIMER
for(int i=0; i<MAX_VALUE; i++) {
result += base->cS();
}
END_TIMER
delete base;
cout << "Result " << result << endl;
PRINT_TIMER
}
{
cout << "dynamic_cast version " << endl;
BASE* base = new C;
long result = 0;
START_TIMER
for(int i=0; i<MAX_VALUE; i++) {
result += base->c();
}
END_TIMER
delete base;
cout << "Result " << result << endl;
PRINT_TIMER
}
}
I would like to know comments about that. I also would like to see an
example
in wich dynamic_cast cannot be absolutely removed.
Cheers.
Gianguglielmo