次の適切な用途は何ですか:
static_castdynamic_castconst_castreinterpret_cast- C スタイル キャスト
(type)value - 関数スタイルのキャスト
type(value)
どの特定のケースでどちらを使用するかをどのように決定しますか?
static_cast使用を試みる最初のキャストです。型間の暗黙的な変換 ( inttofloatや pointer toなどvoid*) のようなことを行い、明示的な変換関数 (または暗黙的な変換関数) を呼び出すこともできます。多くの場合、明示的に記述する必要はありませんが、構文は同等であり、避けるべきであることstatic_castに注意することが重要です (詳細は後述)。ただし、 Aは安全であり、コンストラクターを呼び出すことが保証されています。T(something)(T)somethingT(something, something_else)
static_cast継承階層を介してキャストすることもできます。virtual上向き (基底クラス) にキャストする場合は不要ですが、下向きにキャストする場合は、継承によるキャストでない限り使用できます。ただし、チェックは行われstatic_castず、実際にはオブジェクトの型ではない型に階層を下げることは未定義の動作です。
const_castconst変数を削除または追加するために使用できます。他の 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)objectorを使用したキャストであり、機能的に同等です。type(object)これらは、次のうち最初に成功したものとして定義されます。
const_caststatic_cast(アクセス制限は無視していますが)static_cast(上記を参照)、その後const_castreinterpret_castreinterpret_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++ キャストを使用する場合: