質問
のためのシステムに変換する必要があるのを指すポインター長の長さのポインタ型です。でお分かりだと思うことは非常に安全ではない。私は利用dynamic_castに変換す混合しない場合、nullポインタです。このページと http://publib.boulder.ibm.com/infocenter/lnxpcomp/v7v91/index.jsp?topic=/com.ibm.vacpp7l.doc/language/ref/clrc05keyword_dynamic_cast.htm
のdynamic_castを行うオペレーター 型変換を実行す。の dynamic_castオペレーターを保証 変換のポインタをベース クラスへのポインタを導出クラス や変換のlvalue つの基本クラス 参考に導出クラスです。A プログラムを使用しな 階層ます。このオペレーターと をtypeidオペレーターを実行時 種別情報(RTTI支援 C++.
ていただきたいと思いますようになったのだが、エラーの場合はnullで書いた自動キャスト
template<class T, class T2> T mydynamic_cast(T2 p)
{
assert(dynamic_cast<T>(p));
return reinterpret_cast<T>(p);
}
とMSVCを取得します。エラーエラー C2681:'長':無効な表現型dynamic_cast".もこのワークを仮想機能...作!さんのダイナミックキャストの上下に鋳造相続の問題もあったの型にキャストの問題ます。思いがreinterpret_castがることを保証するものではありません、同じタイプの安全性です。
どうすれば良いチェックに使用する場合網同じです。かを比較し、両タイプidをしてください問題になりたいときに網を生み出すものです。ではなぜです。
解決
Cインターフェースのみをサポートする言語で記述されたアプリでC ++ DLLをロードする場合、同様のことをしなければなりませんでした。予期しないオブジェクトタイプが渡された場合、すぐにエラーを表示するソリューションを次に示します。これにより、問題が発生した場合の診断がはるかに簡単になります。
トリックは、ハンドルとして渡すすべてのクラスが共通の基本クラスから継承する必要があるということです。
#include <stdexcept>
#include <typeinfo>
#include <string>
#include <iostream>
using namespace std;
// Any class that needs to be passed out as a handle must inherit from this class.
// Use virtual inheritance if needed in multiple inheritance situations.
class Base
{
public:
virtual ~Base() {} // Ensure a v-table exists for RTTI/dynamic_cast to work
};
class ClassA : public Base
{
};
class ClassB : public Base
{
};
class ClassC
{
public:
virtual ~ClassC() {}
};
// Convert a pointer to a long handle. Always use this function
// to pass handles to outside code. It ensures that T does derive
// from Base, and that things work properly in a multiple inheritance
// situation.
template <typename T>
long pointer_to_handle_cast(T ptr)
{
return reinterpret_cast<long>(static_cast<Base*>(ptr));
}
// Convert a long handle back to a pointer. This makes sure at
// compile time that T does derive from Base. Throws an exception
// if handle is NULL, or a pointer to a non-rtti object, or a pointer
// to a class not convertable to T.
template <typename T>
T safe_handle_cast(long handle)
{
if (handle == NULL)
throw invalid_argument(string("Error casting null pointer to ") + (typeid(T).name()));
Base *base = static_cast<T>(NULL); // Check at compile time that T converts to a Base *
base = reinterpret_cast<Base *>(handle);
T result = NULL;
try
{
result = dynamic_cast<T>(base);
}
catch(__non_rtti_object &)
{
throw invalid_argument(string("Error casting non-rtti object to ") + (typeid(T).name()));
}
if (!result)
throw invalid_argument(string("Error casting pointer to ") + typeid(*base).name() + " to " + (typeid(T).name()));
return result;
}
int main()
{
ClassA *a = new ClassA();
ClassB *b = new ClassB();
ClassC *c = new ClassC();
long d = 0;
long ahandle = pointer_to_handle_cast(a);
long bhandle = pointer_to_handle_cast(b);
// long chandle = pointer_to_handle_cast(c); //Won't compile
long chandle = reinterpret_cast<long>(c);
// long dhandle = pointer_to_handle_cast(&d); Won't compile
long dhandle = reinterpret_cast<long>(&d);
// send handle to library
//...
// get handle back
try
{
a = safe_handle_cast<ClassA *>(ahandle);
//a = safe_handle_cast<ClassA *>(bhandle); // fails at runtime
//a = safe_handle_cast<ClassA *>(chandle); // fails at runtime
//a = safe_handle_cast<ClassA *>(dhandle); // fails at runtime
//a = safe_handle_cast<ClassA *>(NULL); // fails at runtime
//c = safe_handle_cast<ClassC *>(chandle); // Won't compile
}
catch (invalid_argument &ex)
{
cout << ex.what() << endl;
}
return 0;
}
他のヒント
dynamic_cast
は、継承を通じて関連付けられたクラス間でのみ使用できます。ポインターをlongまたはその逆に変換するには、reinterpret_cast
を使用できます。ポインターがヌルかどうかを確認するには、assert(ptr != 0)
を使用します。ただし、通常は<=>を使用することはお勧めできません。ポインターをlongに変換する必要があるのはなぜですか?
別のオプションは、ユニオンを使用することです:
union U {
int* i_ptr_;
long l;
}
繰り返しますが、ユニオンもほとんど必要ありません。
Windows 64では、ポインターは64ビット量になりますが、long
は32ビット量になり、コードが破損することに注意してください。少なくとも、プラットフォームに基づいて整数型を選択する必要があります。 MSVCが、ポインタを保持するためにC99で提供されているタイプであるuintptr_t
をサポートしているかどうかはわかりません。使用可能な場合、これが最適なタイプになります。
その他については、dynamic_cast
vs reinterpret_cast
の理由と理由を十分に説明している人もいます。
reinterpret_castは、ここで使用する正しいキャストです。
これはほとんど安全に行える唯一のことです。
ポインター型から型Tへの元のポインター型へのreinterpret_castは、元のポインターを生成します。 (Tが少なくとも元のポインター型と同じ大きさのポインターまたは整数型であると仮定します)
ポインタ型からTへのreinterpret_castは指定されていないことに注意してください。 T型の値についての保証はありませんが、元の型に戻して再解釈した場合、元の値を取得することを除く。したがって、あなたがあなたのケースで中間の長い値で何もしようとしないと仮定すると、reinterpret_castは完全に安全で移植性があります。
編集:もちろん、2回目のキャストで、元の型が何であるかわからない場合、これは役に立ちません。その場合、あなたはめちゃくちゃです。 longは、どのポインタから変換されたのかについての型情報をどのような形でも伝えることはできません。
reinterpret_cast
を使用して整数型にキャストし、ポインター型に戻すことができます。 整数型がポインター値を格納するのに十分な大きさである場合、その変換はポインター値を変更しません。
他の人がすでに言っているように、非多態性クラスでdynamic_castを使用する動作は定義されていません(とにかく暗黙的でここで無視されるアップキャストを行う場合を除きます)。また、ポインターまたは参照でのみ機能します。整数型ではありません。
さまざまなposixシステムにある::intptr_t
を使用した方がよいでしょう。そのタイプを、キャスト先の中間タイプとして使用できます。
変換が成功するかどうかのチェックについては、sizeof:を使用できます。
BOOST_STATIC_ASSERT(sizeof(T1) >= sizeof(T2));
変換を実行できなかった場合、はコンパイル時に失敗します。または、その条件でアサートを使用し続けると、代わりに実行時にアサートされます。
警告:これは、T以外のタイプのUを使用してT*
をintptr_t
にU*
に戻すことを妨げるものではありません。したがって、これは、キャストが<=>から<=>にキャストしてから<=>に戻す場合は、ポインターの値を変更します。 (ニコラが別の保護を期待するかもしれないと指摘してくれてありがとう。)
だいたい音のように良くないと危険な考えがなければならない(つまりんの作業遺産システムまたはハードウェアということはない)を提供している包装のポインタの種類によって簡単な構造体を含む二つのメンバー:1)voidポインタをオブジェクトインスタンスの文字列、enum、その他ならではのユニークな識別子を伝えてくれるおうとするキャストのvoid*ます。以下に例を示しますのん(注思わざわざこの試験である文法誤りがな):
struct PtrWrapper {
void* m_theRealPointer;
std::string m_type;
};
void YourDangerousMethod( long argument ) {
if ( !argument )
return;
PtrWrapper& pw = *(PtrWrapper*)argument;
assert( !pw.m_type.empty() );
if ( pw.m_type == "ClassA" ) {
ClassA* a = (ClassA*)pw.m_theRealPointer;
a->DoSomething();
} else if (...) { ... }
}
dynamic_cast<>
は、(多態的な意味で) convertible 型でのみ使用することを目的としたキャストです。 pointer
をlong
にキャストすると(サイズの互換性を確保するために、litbはstatic_assertを正しく提案します)、ポインターのタイプに関するすべての情報が失われます。ポインタを戻すためのsafe_reinterpret_cast<>
を実装する方法はありません:値と型の両方。
意味を明確にするために:
struct a_kind {};
struct b_kind {};
void function(long ptr)
{}
int
main(int argc, char *argv[])
{
a_kind * ptr1 = new a_kind;
b_kind * ptr2 = new b_kind;
function( (long)ptr1 );
function( (long)ptr2 );
return 0;
}
function()
が渡されたポインタの種類と<!> quot; down <!> quot;を判別する方法はありません。次のいずれかの場合を除き、適切な型にキャストします。
- longは、型の情報を持つオブジェクトによってラップされます。
- 型自体は、参照されるオブジェクトにエンコードされます。
両方の解決策はareいため、RTTIの代理であるため、避ける必要があります。
また、longの代わりにsize_tを使用することをお勧めします-このタイプは、アドレス空間のサイズと互換性があることが保証されていると思います。
ポインタをlong型にキャストすることに決めた直後に、タイプセーフティを風に投げました。
dynamic_castは、<!> ampをキャストするために使用されます。派生ツリーを下る。つまり、基本クラスポインターから派生クラスポインターへ。お持ちの場合:
class Base
{
};
class Foo : public Base
{
};
class Bar : public Base
{
};
この方法でdynamic_castを使用できます...
Base* obj = new Bar;
Bar* bar = dynamic_cast<Bar*>(obj); // this returns a pointer to the derived type because obj actually is a 'Bar' object
assert( bar != 0 );
Foo* foo = dynamic_cast<Foo*>(obj); // this returns NULL because obj isn't a Foo
assert( foo == 0 );
...ただし、動的キャストを使用して派生ツリーからキャストインすることはできません。そのためにはreinterpret_castまたはCスタイルのキャストが必要です。