ポインタが他のクラスにキャスト可能か調べる(2)
の続き
VS2005 の dynamic_cast<> が最強すぎる件。
#include <typeinfo.h> extern "C" void* __cdecl __RTDynamicCast(void* inptr, long unknown, void* SrcType, void* TargetType, int isReference); struct A { virtual ~A() { } }; struct B : public A { }; void main() { B b; A* pa = &b; void* p = pa; void* p2 = __RTDynamicCast(p, 0, (void*)&typeid(*pa), (void*)&typeid(B), false); if (p2 != NULL) { printf("成功: %s\n", typeid(*pa).name()); } else { printf("失敗: %s\n", typeid(*pa).name()); } void* p3 = __RTDynamicCast(p, 0, (void*)&typeid(A), (void*)&typeid(B), false); if (p3 != NULL) { printf("成功: %s\n", typeid(A).name()); } else { printf("失敗: %s\n", typeid(A).name()); } }
結果
失敗: struct B 成功: struct A
ネット上でいくつか探してきた __RTDynamicCast の実装は、SrcType に &typeid(int) を渡しても平気でキャストしてくれていたのですが、本来の VS2005 の __RTDynamicCast を使ってみると、(typeid(*pa)ではなく)dynamic_cast<>(ここ) に入っている型を指定しないと NULL が返されてしまうようです。
どうやってこんなの実装してるんだ……。
追記:
もうちょい調べてみると、SrcType は TargetType より上位のクラスを指定しないとダメというだけのようです。
つまりダウンキャスト以外の用途には使えないってことですね。
あと、多重継承を行っている場合は、結構いろいろとキャスト出来るみたいです。
どのみちダウンキャスト以外の用途には使えないようですが……。
試しに VS2005 で上位クラスに dynamic_cast<> してみましたが、__RTDynamicCast() は呼び出されずにそのまま代入されているだけでした。
以下のテストコード
#include <typeinfo.h> extern "C" void* __cdecl __RTDynamicCast(void* inptr, long unknown, void* SrcType, void* TargetType, int isReference); struct A { virtual ~A() { } }; struct B : public A { }; struct C : public B { }; struct D { virtual ~D() { } }; struct E : public C, public D { }; template<class TSrc, class TTarget> void test(void* value) { void* p = __RTDynamicCast(value, 0, (void*)&typeid(TSrc), (void*)&typeid(TTarget), false); if (p != NULL) { ::printf("SUCCEEDED: src = %s, target = %s\n", typeid(TSrc).name(), typeid(TTarget).name()); } else { ::printf("FAILED : src = %s, target = %s\n", typeid(TSrc).name(), typeid(TTarget).name()); } } void main() { { ::printf("---- 元の型が C ----\n"); C c; void* p = &c; test<A, A>(p); test<B, A>(p); test<C, A>(p); ::printf("\n"); test<A, B>(p); test<B, B>(p); test<C, B>(p); ::printf("\n"); test<A, C>(p); test<B, C>(p); test<C, C>(p); ::printf("\n"); } { ::printf("---- 元の型が E で、C にキャストして取得 ----\n"); E e; void* p = (C*)&e; test<A, A>(p); test<B, A>(p); test<C, A>(p); test<D, A>(p); test<E, A>(p); ::printf("\n"); test<A, B>(p); test<B, B>(p); test<C, B>(p); test<D, B>(p); test<E, B>(p); ::printf("\n"); test<A, C>(p); test<B, C>(p); test<C, C>(p); test<D, C>(p); test<E, C>(p); ::printf("\n"); test<A, D>(p); test<B, D>(p); test<C, D>(p); test<D, D>(p); test<E, D>(p); ::printf("\n"); test<A, E>(p); test<B, E>(p); test<C, E>(p); test<D, E>(p); test<E, E>(p); ::printf("\n"); } { ::printf("---- 元の型が E で、D にキャストして取得 ----\n"); E e; void* p = (D*)&e; test<A, A>(p); test<B, A>(p); test<C, A>(p); test<D, A>(p); test<E, A>(p); ::printf("\n"); test<A, B>(p); test<B, B>(p); test<C, B>(p); test<D, B>(p); test<E, B>(p); ::printf("\n"); test<A, C>(p); test<B, C>(p); test<C, C>(p); test<D, C>(p); test<E, C>(p); ::printf("\n"); test<A, D>(p); test<B, D>(p); test<C, D>(p); test<D, D>(p); test<E, D>(p); ::printf("\n"); test<A, E>(p); test<B, E>(p); test<C, E>(p); test<D, E>(p); test<E, E>(p); ::printf("\n"); } return 0; }
---- 元の型が C ---- FAILED : src = struct A, target = struct A FAILED : src = struct B, target = struct A FAILED : src = struct C, target = struct A SUCCEEDED: src = struct A, target = struct B FAILED : src = struct B, target = struct B FAILED : src = struct C, target = struct B SUCCEEDED: src = struct A, target = struct C SUCCEEDED: src = struct B, target = struct C FAILED : src = struct C, target = struct C ---- 元の型が E で、C にキャストして取得 ---- SUCCEEDED: src = struct A, target = struct A SUCCEEDED: src = struct B, target = struct A SUCCEEDED: src = struct C, target = struct A FAILED : src = struct D, target = struct A SUCCEEDED: src = struct E, target = struct A SUCCEEDED: src = struct A, target = struct B SUCCEEDED: src = struct B, target = struct B SUCCEEDED: src = struct C, target = struct B FAILED : src = struct D, target = struct B SUCCEEDED: src = struct E, target = struct B SUCCEEDED: src = struct A, target = struct C SUCCEEDED: src = struct B, target = struct C SUCCEEDED: src = struct C, target = struct C FAILED : src = struct D, target = struct C SUCCEEDED: src = struct E, target = struct C SUCCEEDED: src = struct A, target = struct D SUCCEEDED: src = struct B, target = struct D SUCCEEDED: src = struct C, target = struct D FAILED : src = struct D, target = struct D SUCCEEDED: src = struct E, target = struct D SUCCEEDED: src = struct A, target = struct E SUCCEEDED: src = struct B, target = struct E SUCCEEDED: src = struct C, target = struct E FAILED : src = struct D, target = struct E SUCCEEDED: src = struct E, target = struct E ---- 元の型が E で、D にキャストして取得 ---- FAILED : src = struct A, target = struct A FAILED : src = struct B, target = struct A FAILED : src = struct C, target = struct A SUCCEEDED: src = struct D, target = struct A FAILED : src = struct E, target = struct A FAILED : src = struct A, target = struct B FAILED : src = struct B, target = struct B FAILED : src = struct C, target = struct B SUCCEEDED: src = struct D, target = struct B FAILED : src = struct E, target = struct B FAILED : src = struct A, target = struct C FAILED : src = struct B, target = struct C FAILED : src = struct C, target = struct C SUCCEEDED: src = struct D, target = struct C FAILED : src = struct E, target = struct C FAILED : src = struct A, target = struct D FAILED : src = struct B, target = struct D FAILED : src = struct C, target = struct D SUCCEEDED: src = struct D, target = struct D FAILED : src = struct E, target = struct D FAILED : src = struct A, target = struct E FAILED : src = struct B, target = struct E FAILED : src = struct C, target = struct E SUCCEEDED: src = struct D, target = struct E FAILED : src = struct E, target = struct E