正しい使い方は何ですか?
static_cast
dynamic_cast
const_cast
reinterpret_cast
(type)value
type(value)
どの特定の場合にどのように使用するかをどのように決定しますか?
static_cast
は最初に使うべきキャストです。型間の暗黙的な変換(int
からfloat
へのポインタ、またはvoid*
へのポインタなど)などの処理を行い、明示的な変換関数(または暗黙的な変換関数)を呼び出すこともできます。多くの場合、明示的にstatic_cast
を記述する必要はありませんが、T(something)
構文は(T)something
と同等であり、避けるべきであることに注意することが重要です。 T(something, something_else)
は安全ですが、コンストラクタを呼び出すことが保証されています。
static_cast
は継承階層を介してキャストすることもできます。上向きに(基本クラスに向かって)キャストする場合は不要ですが、下向きにキャストする場合は、virtual
継承を介してキャストしない限り使用できます。ただし、チェックは行いません。実際にはオブジェクトの型ではない型に階層をstatic_cast
することは、未定義の動作です。
const_cast
は、変数からconst
を削除または追加するために使用できます。他のC++キャストで削除することはできません(reinterpret_cast
でさえも)。元の変数がconst
の場合、以前のconst
値を変更することは未定義であることに注意することが重要です。 const
で宣言されていないものへの参照からconst
を外すためにそれを使用する場合、それは安全です。これは、たとえばconst
に基づいてメンバ関数をオーバーロードするときに便利です。メンバ関数のオーバーロードを呼び出すなど、オブジェクトにconst
を追加するためにも使用できます。
const_cast
はvolatile
でも同様に機能しますが、あまり一般的ではありません。
dynamic_cast
は多態性を扱うためだけに使われます。多相型へのポインタまたは参照を他のクラス型にキャストすることができます(多相型には、宣言または継承された少なくとも1つの仮想関数があります)。あなたは単に下方にキャストすること以上にそれを使うことができます - あなたは横にキャストすることができますまたはさらに別のチェーンの上にキャストすることができます。 dynamic_cast
は目的のオブジェクトを探し出し、可能であればそれを返します。それができない場合は、ポインタの場合はnullptr
を返すか、参照の場合はstd::bad_cast
をスローします。
ただし、dynamic_cast
にはいくつかの制限があります。継承階層内に同じ型のオブジェクトが複数存在している場合(いわゆる 'ひし形')、virtual
継承を使用していない場合は機能しません。また、パブリック継承のみを通過することもできます。常にprotected
またはprivate
継承を通過することはできません。ただし、このような形式の継承はめったにないため、これはめったに問題になりません。
reinterpret_cast
は最も危険なキャストであり、慎重に使用してください。あるポインタから別のポインタに値をキャストしたり、ポインタをint
に格納したり、その他のあらゆる厄介なことに使用するなど、あるタイプを別のタイプに直接変換します。 reinterpret_cast
で得られる唯一の保証は、通常、結果を元の型にキャストバックした場合、まったく同じ値が返されるということです(ただし、中間型がより小さい場合はnot元のタイプ) reinterpret_cast
では実行できない変換も多数あります。生のデータストリームを実際のデータに変換したり、整列ポインタの下位ビットにデータを格納するなど、特に変な変換やビット操作に主に使用されます。
C-style castおよびfunction-style castは、それぞれ(type)object
またはtype(object)
を使用したキャストであり、機能的に同等です。これらは、成功した次のうちの最初のものとして定義されます。
const_cast
static_cast
(ただし、アクセス制限は無視されます)static_cast
(上記参照)、そしてconst_cast
reinterpret_cast
reinterpret_cast
、次にconst_cast
したがって、場合によっては他のキャストの代わりとして使用できますが、reinterpret_cast
に解決する機能があるため非常に危険な場合があります。明示的なキャストが必要な場合は、static_cast
が成功するかどうかを確認してください。 reinterpret_cast
は失敗します。それでも、もっと長く、より明確な選択肢を考えてください。
Cスタイルのキャストでは、static_cast
の実行時にアクセス制御も無視されます。つまり、他のキャストでは不可能な操作を実行できます。ただし、これはほとんど問題ではありません。私の考えでは、Cスタイルのキャストを避けるもう1つの理由です。
継承階層内のポインタ/参照を変換するためにdynamic_cast
を使います。
通常の型変換にはstatic_cast
を使用してください。
ビットパターンの低レベルの再解釈にはreinterpret_cast
を使用してください。細心の注意を払って使用してください。
const_cast
を捨てるためにconst/volatile
を使用してください。 const-incorrect APIを使用しているのでない限り、これを避けてください。
(上記で理論的および概念的な説明がたくさんあります)
static_cast 、 dynamic_cast 、 const_cast 、 reinterpret_cast を使用したときの 実用例 .
(また、説明を理解するためにこれを参照してください: http://www.cplusplus.com/doc/tutorial/typecasting/ )
static_cast:
OnEventData(void* pData)
{
......
// pData is a void* pData,
// EventData is a structure e.g.
// typedef struct _EventData {
// std::string id;
// std:: string remote_id;
// } EventData;
// On Some Situation a void pointer *pData
// has been static_casted as
// EventData* pointer
EventData *evtdata = static_cast<EventData*>(pData);
.....
}
dynamic_cast:
void DebugLog::OnMessage(Message *msg)
{
static DebugMsgData *debug;
static XYZMsgData *xyz;
if(debug = dynamic_cast<DebugMsgData*>(msg->pdata)){
// debug message
}
else if(xyz = dynamic_cast<XYZMsgData*>(msg->pdata)){
// xyz message
}
else/* if( ... )*/{
// ...
}
}
const_cast:
// *Passwd declared as a const
const unsigned char *Passwd
// on some situation it require to remove its constness
const_cast<unsigned char*>(Passwd)
reinterpret_cast:
typedef unsigned short uint16;
// Read Bytes returns that 2 bytes got read.
bool ByteBuffer::ReadUInt16(uint16& val) {
return ReadBytes(reinterpret_cast<char*>(&val), 2);
}
あなたが少しの内部を知っているなら、それは役に立つかもしれません...
static_cast
static_cast
を使ってください。A
からB
への変換を依頼すると、static_cast
はB
をparamとして渡してA
のコンストラクタを呼び出します。あるいは、A
は変換演算子(すなわちA::operator B()
)を持つことができます。 B
がそのようなコンストラクタを持っていないか、A
が変換演算子を持っていない場合は、コンパイル時エラーが発生します。 A*
からB*
へのキャストは常に成功します。そうしないと、コンパイルエラーが発生します。A&
からB&
まで。dynamic_cast
(Base*)
から(Derived*)
は失敗する可能性があります。A*
からB*
の場合、キャストが無効な場合、dynamic_castはnullptrを返します。A&
からB&
のキャストが無効な場合、dynamic_castはbad_cast例外をスローします。const_cast
set<T>
のようなコンテナを反復処理することです。しかし、あなたの目的がオブジェクトの非キーメンバーを変更することであれば、それは問題ないはずです。あなたはconstnessを削除するためにconst_castを使うことができます。T& foo()
とconst T& foo()
を実装したい場合です。コードの重複を避けるために、ある関数の値を別の関数から返すためにconst_castを適用することができます。reinterpret_cast
これまでの他の答えに加えて、これはstatic_cast
が十分ではないのでreinterpret_cast
が必要とされる明白でない例です。出力パラメータに異なるクラスのオブジェクトへのポインタを返す(共通の基本クラスを共有しない)関数があるとします。そのような関数の実際の例は CoCreateInstance()
です(最後のパラメータ、実際にはvoid**
を参照)。この関数から特定のクラスのオブジェクトを要求するとします。そのため、ポインタの型はあらかじめわかっています(これはCOMオブジェクトに対してよく行われます)。この場合、あなたはあなたのポインタへのポインタをvoid**
でstatic_cast
にキャストすることはできません:あなたはreinterpret_cast<void**>(&yourPointer)
を必要とします。
コードでは:
#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
//static_cast<void**>(&pNetFwPolicy2) would give a compile error
reinterpret_cast<void**>(&pNetFwPolicy2) );
ただし、static_cast
は単純なポインタ(ポインタへのポインタではない)に対して機能するため、次のようにreinterpret_cast
を回避するように上記のコードを書き換えることができます。
#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
void* tmp = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
&tmp );
pNetFwPolicy2 = static_cast<INetFwPolicy2*>(tmp);
他の回答ではC++キャスト間のすべての違いについてうまく説明されていますが、Cスタイルのキャスト(Type) var
およびType(var)
を使用してはいけない理由を少し説明します。
C++初心者にとっては、CスタイルキャストはC++キャスト(static_cast <>()、dynamic_cast <>()、const_cast <>()、reinterpret_cast <>())のスーパーセット操作であるように見え、誰かがC++キャストより優先します。 。実際にはCスタイルのキャストがスーパーセットであり、書くのがより短いです。
Cスタイルキャストの主な問題は、開発者がキャストを意図していないことです。 Cスタイルのキャストでは、static_cast <>()およびdynamic_cast <>()による通常の安全なキャストからconst_cast <>()のような潜在的に危険なキャストまで、事実上すべての種類のキャストが可能です。整数値をポインタに再解釈することさえ可能な、修正およびreinterpret_cast <>()が可能です。
これがサンプルです。
int a=Rand(); // Random number.
int* pa1=reinterpret_cast<int*>(a); // OK. Here developer clearly expressed he wanted to do this potentially dangerous operation.
int* pa2=static_cast<int*>(a); // Compiler error.
int* pa3=dynamic_cast<int*>(a); // Compiler error.
int* pa4=(int*) a; // OK. C-style cast can do such cast. The question is if it was intentional or developer just did some typo.
*pa4=5; // Program crashes.
C++キャストが言語に追加された主な理由は、開発者が自分の意図を明確にできるようにするためでした - なぜ彼がそのキャストをするつもりなのか。 C++で完全に有効なCスタイルのキャストを使用することで、特にコードを作成しなかった他の開発者にとって、コードが読みにくくなり、エラーが発生しやすくなります。そのため、コードをより読みやすく明示的にするためには、常にCスタイルのキャストよりもC++のキャストを好むべきです。
これはBjarne Stroustrup(C++の作者)の本The C++ Programming Language第4版 - 302ページからの短い引用です。
このCスタイルのキャストは、名前の付いた変換演算子よりもはるかに危険です。これは、大規模プログラムでは表記が難しく、プログラマが意図している変換の種類が明示的ではないためです。
理解するために、以下のコードスニペットを考えてみましょう。
struct Foo{};
struct Bar{};
int main(int argc, char** argv)
{
Foo* f = new Foo;
Bar* b1 = f; // (1)
Bar* b2 = static_cast<Bar*>(f); // (2)
Bar* b3 = dynamic_cast<Bar*>(f); // (3)
Bar* b4 = reinterpret_cast<Bar*>(f); // (4)
Bar* b5 = const_cast<Bar*>(f); // (5)
return 0;
}
行(4)のみがエラーなしでコンパイルされます。 reinterpret_castのみを使用して、オブジェクトへのポインターを無関係なオブジェクトタイプへのポインターに変換できます。
注目すべきことは次のとおりです。dynamic_castは実行時に失敗しますが、ほとんどのコンパイラでは、キャストされるポインタの構造に仮想関数がないため、コンパイルも失敗します。 dynamic_castは、ポリモーフィッククラスポインターのみで機能します。
C++キャストを使用する場合: