静的キャスト
静的キャストは、互換性のある型間の変換を実行します。C スタイルのキャストに似ていますが、より制限があります。たとえば、C スタイルのキャストでは、整数ポインターが char を指すことができます。
char c = 10; // 1 byte
int *p = (int*)&c; // 4 bytes
これにより、割り当てられたメモリの 1 バイトを指す 4 バイトのポインタが生成されるため、このポインタに書き込むと、実行時エラーが発生するか、隣接するメモリが上書きされます。
*p = 5; // run-time error: stack corruption
C スタイルのキャストとは対照的に、静的キャストを使用すると、コンパイラーはポインターとポイント対象のデータ型に互換性があることを確認できます。これにより、プログラマーはコンパイル中にこの誤ったポインターの割り当てを見つけることができます。
int *q = static_cast<int*>(&c); // compile-time error
キャストの再解釈
ポインター変換を強制するには、C スタイルのキャストがバックグラウンドで行うのと同じ方法で、代わりに再解釈キャストが使用されます。
int *r = reinterpret_cast<int*>(&c); // forced conversion
このキャストは、あるポインター型から別の互換性のないポインター型への変換など、特定の無関係な型間の変換を処理します。基になるビット パターンを変更せずに、データのバイナリ コピーを実行するだけです。このような低レベル操作の結果はシステム固有のものであり、移植性がないことに注意してください。完全に回避できない場合は、注意して使用する必要があります。
動的キャスト
これは、オブジェクト ポインターとオブジェクト参照を、継承階層内の他のポインターまたは参照型に変換するためにのみ使用されます。ポインターが変換先の型の完全なオブジェクトを参照することを実行時にチェックすることによって、ポインターが指すオブジェクトを変換できることを確認する唯一のキャストです。この実行時チェックを可能にするには、オブジェクトがポリモーフィックである必要があります。つまり、クラスは少なくとも 1 つの仮想関数を定義または継承する必要があります。これは、コンパイラがそのようなオブジェクトに必要なランタイム型情報のみを生成するためです。
動的キャストの例
次の例では、動的キャストを使用MyChild
してポインタをポインタに変換しています。MyBase
Child オブジェクトには完全な Base オブジェクトが含まれているため、この派生からベースへの変換は成功します。
class MyBase
{
public:
virtual void test() {}
};
class MyChild : public MyBase {};
int main()
{
MyChild *child = new MyChild();
MyBase *base = dynamic_cast<MyBase*>(child); // ok
}
MyBase
次の例では、ポインターをポインターに変換しようとしていMyChild
ます。Base オブジェクトには完全な Child オブジェクトが含まれていないため、このポインター変換は失敗します。これを示すために、動的キャストは null ポインターを返します。これにより、実行時に変換が成功したかどうかを確認する便利な方法が提供されます。
MyBase *base = new MyBase();
MyChild *child = dynamic_cast<MyChild*>(base);
if (child == 0)
std::cout << "Null pointer returned";
ポインターの代わりに参照が変換されると、動的キャストはbad_cast
例外をスローして失敗します。try-catch
これは、ステートメントを使用して処理する必要があります。
#include <exception>
// …
try
{
MyChild &child = dynamic_cast<MyChild&>(*base);
}
catch(std::bad_cast &e)
{
std::cout << e.what(); // bad dynamic_cast
}
動的キャストまたは静的キャスト
動的キャストを使用する利点は、実行時に変換が成功したかどうかをプログラマーが確認できることです。欠点は、このチェックの実行に関連するパフォーマンスのオーバーヘッドがあることです。このため、最初の例では、派生からベースへの変換が決して失敗しないため、静的キャストを使用することをお勧めします。
MyBase *base = static_cast<MyBase*>(child); // ok
ただし、2 番目の例では、変換は成功する場合と失敗する場合があります。MyBase
オブジェクトにインスタンスが含まれている場合は失敗し、MyBase
インスタンスが含まれている場合は成功しMyChild
ます。状況によっては、これは実行時までわからないことがあります。この場合、動的キャストは静的キャストよりも適切な選択です。
// Succeeds for a MyChild object
MyChild *child = dynamic_cast<MyChild*>(base);
動的キャストの代わりに静的キャストを使用してベースから派生への変換が実行された場合、変換は失敗しませんでした。不完全なオブジェクトを参照するポインターが返されます。このようなポインターを逆参照すると、実行時エラーが発生する可能性があります。
// Allowed, but invalid
MyChild *child = static_cast<MyChild*>(base);
// Incomplete MyChild object dereferenced
(*child);
コンストキャスト
これは主const
に、変数の修飾子を追加または削除するために使用されます。
const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // removes const
キャストを使用すると定数の値を変更できますがconst
、これは依然として無効なコードであり、実行時エラーが発生する可能性があります。これは、たとえば、定数が読み取り専用メモリのセクションにある場合に発生する可能性があります。
*nonConst = 10; // potential run-time error
const
代わりにキャストは主に、非定数ポインター引数を取る関数がある場合に使用されますが、それはポインティーを変更しません。
void print(int *p)
{
std::cout << *p;
}
const
その後、キャストを使用して関数に定数変数を渡すことができます。
print(&myConst); // error: cannot convert
// const int* to int*
print(nonConst); // allowed
ソースとその他の説明