以前から継承されたクラスと何も継承しないクラスでクラス内のメンバ関数を呼び出すときに呼び出しコストに変化があるのかということが気にはなっていたものの、確かめたりすることはありませんでした。今日、後輩と話していて、そんな話題になって改めて確かめてみたくなったので実際に呼び出しコストに差があるのかを検証してみました。
検証対象は基底クラス、9回の継承があるクラス、19回の継承があるクラスとして、2^29回の空のメンバ関数呼び出しを行う試行を30回行い平均時間を計測しました。念のため、それを3回やりました。
環境
IDE: VC++ 2010
OS: Windows 7 64bit
CPU: core-i7 920
Memory: 6GB
実験結果は以下のようになりました。
1回目 --------------------------------------------
基底クラス: 1.735266 sec
9回継承クラス: 1.802300 sec
19回継承クラス: 1.972933 sec
2回目 --------------------------------------------
基底クラス: 1.757333 sec
9回継承クラス: 1.759367 sec
19回継承クラス: 1.952434 sec
3回目 ---------------------------------------------
基底クラス: 1.754667 sec
9回継承クラス: 1.747933 sec
19回継承クラス: 1.937533 sec
基底クラスと9回継承したクラスはほとんど差が見られないですが、19回継承したクラスは明らかに処理時間が増えています。どうやら、ある程度継承を行うと、呼び出しコストは多少なりと増えるようです。
ただ、今回の実験は単純な空のクラスでの話ですので、メンバ変数、メンバ関数が増えた場合はまた違った結果になる可能性があります。また仮想関数を使った場合の検証も結果が変わってくる可能性があるので、暇だったらやってみたいです。
ちなみに、この実験に使ったコードは下記です。wsp::は私の個人ライブラリの関数で、このコードでは時間計測に使っています。
#include <stdio.h>
#include <wsp/core/fn-util.h>
class C1{
public:
void Func(){}
};
class C2: public C1{
public:
void Func(){}
};
class C3: public C2{
public:
void Func(){}
};
class C4: public C3{
public:
void Func(){}
};
class C5: public C4{
public:
void Func(){}
};
class C6: public C5{
public:
void Func(){}
};
class C7: public C6{
public:
void Func(){}
};
class C8: public C7{
public:
void Func(){}
};
class C9: public C8{
public:
void Func(){}
};
class C10: public C9{
public:
void Func(){}
};
class C11: public C10{
public:
void Func(){}
};
class C12: public C11{
public:
void Func(){}
};
class C13: public C12{
public:
void Func(){}
};
class C14: public C13{
public:
void Func(){}
};
class C15: public C14{
public:
void Func(){}
};
class C16: public C15{
public:
void Func(){}
};
class C17: public C16{
public:
void Func(){}
};
class C18: public C17{
public:
void Func(){}
};
class C19: public C18{
public:
void Func(){}
};
class C20: public C19{
public:
void Func(){}
};
void main(){
int n = 1<<29;
int test_num = 30;
float sum = 0.0;
C1 c1;
for(int j=0; j<test_num; ++j){
wsp::StartTimer();
for(int i=0; i<n; ++i){
c1.Func();
}
sum+=wsp::StopTimer();
}
printf("C1: %f sec\n", sum/(float)test_num);
C10 c10;
sum = 0.0;
for(int j=0; j<test_num; ++j){
wsp::StartTimer();
for(int i=0; i<n; ++i){
c10.Func();
}
sum+=wsp::StopTimer();
}
printf("C10: %f sec\n", sum/(float)test_num);
C20 c20;
sum = 0.0;
for(int j=0; j<test_num; ++j){
wsp::StartTimer();
for(int i=0; i<n; ++i){
c20.Func();
}
sum+=wsp::StopTimer();
}
printf("C20: %f sec\n", sum/(float)test_num);
}