次の適切な用途は何ですか:
static_cast
dynamic_cast
const_cast
reinterpret_cast
- C スタイル キャスト
(type)value
- 関数スタイルのキャスト
type(value)
どの特定のケースでどちらを使用するかをどのように決定しますか?
static_cast
使用を試みる最初のキャストです。型間の暗黙的な変換 ( int
tofloat
や pointer toなどvoid*
) のようなことを行い、明示的な変換関数 (または暗黙的な変換関数) を呼び出すこともできます。多くの場合、明示的に記述する必要はありませんが、構文は同等であり、避けるべきであることstatic_cast
に注意することが重要です (詳細は後述)。ただし、 Aは安全であり、コンストラクターを呼び出すことが保証されています。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
は、通常、結果を元の型にキャストして戻すと、まったく同じ値が得られるということです (ただし、中間の型が元の型より小さい場合はそうではありません) 。reinterpret_cast
変換できない変換もいくつかあります。生データストリームを実際のデータに変換したり、ポインタの下位ビットにデータを整列データに格納したりするなど、特に奇妙な変換やビット操作に主に使用されます。
C スタイルのキャストと関数スタイルのキャストは、それぞれ(type)object
orを使用したキャストであり、機能的に同等です。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 が正しくない 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
十分ではないため、reinterpret_cast
必要な明白でない例を次に示します。出力パラメーターで、異なるクラス (共通の基本クラスを共有しない) のオブジェクトへのポインターを返す関数があるとします。そのような関数の実際の例はCoCreateInstance()
(実際には である最後のパラメーターを参照してくださいvoid**
) です。この関数から特定のクラスのオブジェクトを要求すると、ポインターの型が事前にわかっているとします (これは、COM オブジェクトに対してよく行われます)。この場合、ポインターへのポインターをvoid**
withにキャストすることはできませ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);
理解するために、以下のコード スニペットを考えてみましょう。
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だけです。
注意すべきことの 1 つ: dynamic_castは実行時に失敗しますが、ほとんどのコンパイラでは、キャストされるポインターの構造体に仮想関数がないため、コンパイルも失敗します。つまり、dynamic_castはポリモーフィック クラス ポインターでのみ機能します。 .
C++ キャストを使用する場合: