1920

私はCおよびC++コードを20年近く書いていますが、これらの言語には、私が本当に理解したことのない側面が1つあります。私は明らかに通常のキャストを使用しました

MyClass *m = (MyClass *)ptr;

いたるところにありますが、他に2種類のキャストがあるようで、違いはわかりません。次のコード行の違いは何ですか?

MyClass *m = (MyClass *)ptr;
MyClass *m = static_cast<MyClass *>(ptr);
MyClass *m = dynamic_cast<MyClass *>(ptr);
4

8 に答える 8

1757

static_cast

`static_cast`は、いくつかの制限と追加を加えて、基本的に暗黙の変換を元に戻したい場合に使用されます。`static_cast`は実行時チェックを実行しません。これは、特定のタイプのオブジェクトを参照していることがわかっている場合に使用する必要があります。したがって、チェックは不要です。例:
void func(void *data) {
  // Conversion from MyClass* -> void* is implicit
  MyClass *c = static_cast<MyClass*>(data);
  ...
}

int main() {
  MyClass c;
  start_thread(&func, &c)  // func(&c) will be called
      .join();
}

この例では、MyClassオブジェクトを渡したことがわかっているため、これを確認するためのランタイムチェックは必要ありません。

dynamic_cast

`dynamic_cast`は、オブジェクトの動的タイプがわからない場合に役立ちます。参照されるオブジェクトに基本クラスとしてキャストされた型が含まれていない場合は、nullポインターを返します(参照にキャストすると、その場合は `bad_cast`例外がスローされます)。
if (JumpStm *j = dynamic_cast<JumpStm*>(&stm)) {
  ...
} else if (ExprStm *e = dynamic_cast<ExprStm*>(&stm)) {
  ...
}

dynamic_castダウンキャスト(派生クラスにキャスト)し、引数の型がポリモーフィックでない場合は使用できません。たとえば、次のコードはBase仮想関数が含まれていないため、無効です。

struct Base { };
struct Derived : Base { };
int main() {
  Derived d; Base *b = &d;
  dynamic_cast<Derived*>(b); // Invalid
}

「アップキャスト」(基本クラスへのキャスト)は、との両方で常に有効でstatic_castありdynamic_cast、キャストなしでも有効です。「アップキャスト」は暗黙の変換であるためです(基本クラスがアクセス可能である、つまりpublic継承であると想定) 。 。

レギュラーキャスト

これらのキャストは、Cスタイルキャストとも呼ばれます。Cスタイルのキャストは、基本的に、C ++キャストのシーケンスの範囲を試して、最初に機能するC ++キャストを取得することと同じであり、を考慮する必要はありませんdynamic_cast。言うまでもなく、これは、、、のすべてを組み合わせているため、はるかに強力ですがconst_caststatic_castreinterpret_cast使用しないため、安全ではありませんdynamic_cast

さらに、Cスタイルのキャストを使用すると、これを実行できるだけでなく、プライベートベースクラスに安全にキャストすることもできます。「同等の」static_castシーケンスを使用すると、コンパイル時エラーが発生します。

簡潔さのためにCスタイルのキャストを好む人もいます。私はそれらを数値キャストにのみ使用し、ユーザー定義型が含まれる場合は適切なC ++キャストを使用します。これは、より厳密なチェックを提供するためです。

于 2009-08-10T13:50:45.557 に答える
245

静的キャスト

静的キャストは、互換性のある型間の変換を実行します。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してポインタをポインタに変換しています。MyBaseChild オブジェクトには完全な 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

ソースとその他の説明

于 2013-08-24T01:55:13.040 に答える
89

C++プログラミング/型キャストの記事をご覧ください。

さまざまなキャストタイプすべての適切な説明が含まれています。上記のリンクから抜粋したもの:

const_cast

const_cast(expression)const_cast <>()は、変数のconst(ness)(またはvolatile-ness)を追加/削除するために使用されます。

static_cast

static_cast(expression)static_cast <>()は、整数型間でキャストするために使用されます。'eg' char-> long、int->shortなど。

静的キャストは、関連するタイプへのポインターのキャストにも使用されます。たとえば、void*を適切なタイプにキャストします。

dynamic_cast

動的キャストは、実行時にポインターと参照を変換するために使用されます。通常、ポインターまたは参照を継承チェーン(継承階層)の上下にキャストするために使用されます。

dynamic_cast(式)

ターゲット型はポインタ型または参照型である必要があり、式はポインタまたは参照に評価される必要があります。動的キャストは、式が参照するオブジェクトの型がターゲット型と互換性があり、基本クラスに少なくとも1つの仮想メンバー関数がある場合にのみ機能します。そうでない場合で、キャストされる式のタイプがポインターの場合、NULLが返されます。参照での動的キャストが失敗すると、bad_cast例外がスローされます。失敗しない場合、動的キャストは、式が参照されているオブジェクトへのターゲットタイプのポインタまたは参照を返します。

reinterpret_cast

キャストの再解釈は、あるタイプを別のタイプにビット単位でキャストするだけです。ポインタまたは整数型は、再解釈キャストを使用して他の型にキャストできるため、誤用が容易になります。たとえば、キャストを再解釈すると、安全ではないが、整数ポインターを文字列ポインターにキャストする可能性があります。

于 2008-08-26T13:28:43.793 に答える
33

参考までに、Bjarne Stroustrupは、Cスタイルのキャストは避け、可能な限りstatic_castまたはdynamic_castを使用する必要があると述べていると思います。

BarneStroustrupのC++スタイルのFAQ

あなたが何をするかについてそのアドバイスをしてください。私はC++の第一人者にはほど遠いです。

于 2008-08-26T13:39:35.950 に答える
29

C スタイルのキャストは使用しないでください。

C スタイルのキャストは、const キャストと再解釈キャストの混合であり、コード内で見つけて置き換えるのは困難です。C++ アプリケーション プログラマは、C スタイルのキャストを避ける必要があります。

于 2008-09-19T17:30:24.813 に答える
15

Cスタイルのキャストは、const_cast、static_cast、およびreinterpret_castを統合します。

C++にCスタイルのキャストがなかったらいいのにと思います。C ++キャストは適切に目立ち(キャストは通常​​、何か悪いことをしていることを示します)、キャストが実行するさまざまな種類の変換を適切に区別します。また、似たような関数を作成することもできます。たとえば、boost :: lexical_castは、一貫性の観点から非常に優れています。

于 2008-08-26T13:38:35.360 に答える
13

dynamic_castポインタ型と参照型のみをサポートします。NULL型がポインタの場合はキャストが不可能な場合に戻り、型が参照型の場合は例外をスローします。したがって、dynamic_castオブジェクトが特定のタイプであるかどうかを確認するために使用できますが、static_castできません (単に無効な値になってしまいます)。

C スタイル (およびその他の) キャストは、他の回答でカバーされています。

于 2012-02-05T17:10:25.903 に答える
12

dynamic_castランタイムタイプチェックがあり、参照とポインタでのみ機能しますが、static_castランタイムタイプチェックは提供しません。詳細については、MSDNの記事static_castOperatorを参照してください。

于 2008-08-26T13:26:23.707 に答える