実行時のポリモーフィズムが必要だったので、を使用しdynamic_cast
ました。
しかし今、私は2つの問題を抱えていました-dynamic_cast
非常に遅かったです!(下にスクロールしてベンチマークを表示します。)
簡単に言えば、私はこの方法で問題を解決することになりましたstatic_cast
。
struct Base
{
virtual ~Base() { }
virtual int type_id() const = 0;
template<class T>
T *as()
{ return this->type_id() == T::ID ? static_cast<T *>(this) : 0; }
template<class T>
T const *as() const
{ return this->type_id() == T::ID ? static_cast<T const *>(this) : 0; }
};
struct Derived : public Base
{
enum { ID = __COUNTER__ }; // warning: can cause ABI incompatibility
int type_id() const { return ID; }
};
int main()
{
Base const &value = Derived();
Derived const *p = value.as<Derived>(); // "static" dynamic_cast
}
しかし、私は確かにこの問題に遭遇した最初の人ではないので、私はそれが尋ねる価値があるかもしれないと思いました:
このような自家製のソリューションを考え出す代わりに、将来この問題を解決するために使用できる有名なパターン/ライブラリはありますか?
サンプルベンチマーク
私が話していることを理解するために、以下のコードを試してください-私のマシンでの単なる呼び出しよりもdynamic_cast
約 15倍virtual
遅くなりました(以下のコードでは1620ミリ秒に対して110ミリ秒):
#include <cstdio>
#include <ctime>
struct Base { virtual unsigned vcalc(unsigned i) const { return i * i + 1; } };
struct Derived1 : public Base
{ unsigned vcalc(unsigned i) const { return i * i + 2; } };
struct Derived2 : public Derived1
{ unsigned vcalc(unsigned i) const { return i * i + 3; } };
int main()
{
Base const &foo = Derived2();
size_t const COUNT = 50000000;
{
clock_t start = clock();
unsigned n = 0;
for (size_t i = 0; i < COUNT; i++)
n = foo.vcalc(n);
printf("virtual call: %d ms (result: %u)\n",
(int)((clock() - start) * 1000 / CLOCKS_PER_SEC), n);
fflush(stdout);
}
{
clock_t start = clock();
unsigned n = 0;
for (size_t i = 0; i < COUNT; i++)
n = dynamic_cast<Derived1 const &>(foo).vcalc(n);
printf("virtual call after dynamic_cast: %d ms (result: %u)\n",
(int)((clock() - start) * 1000 / CLOCKS_PER_SEC), n);
fflush(stdout);
}
return 0;
}
単語virtual
を削除してに変更dynamic_cast
するとstatic_cast
、実行時間は79ミリ秒になります。したがって、仮想呼び出しは静的呼び出しよりも最大25%遅くなります。