この投稿は、C ++の型変換演算子についてさまざまなソースから読んだり聞いたりしたすべてを要約する試みです。 この情報の主な目的は、C ++を比較的短期間研究したことがある人であり、これらの演算子の使用の詳細を理解するのに役立つと思われます。 古いタイマーとC ++の達人は、おそらく私が説明した図を補足または修正するのに役立つでしょう。 猫の下に興味のある人を招待します。
C型キャスト(Cスタイルキャスト)
C言語のスタイルでの型キャストは、任意の型の式を他の任意の型のデータにキャストできます(例外は、キャストのルールが定義されていない場合の値によるカスタムタイプのキャスト、および実際のタイプのポインターへのキャスト、またはその逆です)。 たとえば、unsigned intはdoubleへのポインターに変換できます。 この型キャスト方法は、C ++で使用できます。 ただし、Cスタイルのキャストメソッドは、static_castとdynamic_castがそれぞれコンパイル時と実行時にできるように、互換性の型チェックを行いません。 同時に、const_castを知ることができ、このキャスト方法でできるreinterpret_castができるすべてのことができます。
キャストの一般的なビュー:
(new_type)exp
ここで、 new_typeは変換後の新しい型であり、 expは新しい型にキャストされる式です。
なぜなら この演算子には予約キーワード(static_castなど)はありませんが、必要に応じてプログラムテキスト内のすべての型変換の場所を見つけるのはあまり便利ではありません。
例を表示
#include <iostream> // // struct AAA{ }; struct BBB{ }; // BBB struct BBB_X:BBB{ }; struct BBB_Y:BBB{ }; int main() { // int i = 5; double d = 111.222; char c = 'a'; int* pi = &i; double * pd = &d; const int* cpi = &i; void* v = NULL; // AAA A; BBB B; BBB_X BX; BBB_Y BY; // AAA* pA = &A; BBB* pB = &B; BBB_X* pBX = &BX; BBB_Y* pBY = &BY; // double int i = (int)d; // d = (double)i; // int char c = (char)pi; //char void v = (void*)c; // void int pi = (int*)v; // const int* pi = (int *) cpi; // AAA BBB // pA = (AAA*) pB; // double double d = (double)pd;//!!! // ? pd = (double*)d;//!!! // pB = (BBB*)pBX; pBY = (BBB_Y*) pB; return 0; }
const_cast
const_castキャスト演算子は、元のデータ型(単純型、ユーザー型、ポインター、参照)からconstおよびvolatile修飾子を削除または追加します。 たとえば、const intがあり、変換後にintになった、またはその逆です。 修飾子constおよびvolatileはcv-qualifiersと呼ばれます。 これらの修飾子の前には型名が付きます。 推測がどれほど困難であっても、const修飾子は定数を設定します。 変数を変更から保護します。 volatile修飾子は、変数の値が明示的に割り当てなくても変更できることを示します。 これにより、この変数を使用した操作のコンパイラによる最適化に対する保護が提供されます。
キャストの一般的なビュー:
const_cast <new_type>(exp)
例を表示
#include <iostream> // void test_func_X(const int* in1, const int& in2) { int *p; // 33 p = const_cast<int*>(in1); *p = 33; // 55 const_cast<int&>(in2) = 55; } // void test_func_Y(int* in1, int& in2) { const int *p; // // 33 p = const_cast<const int*>(in1); *p = 33;// !!! // // 33 const_cast<const int&>(in2) = 55;//!!! } // volatile void test_func_Z(volatile int* in1, volatile int& in2) { int *p; // volatile 33 p = const_cast<int*>(in1); *p = 33; // volatile 55 const_cast<int&>(in2) = 55; } // volatile void test_func_A(int* in1, int& in2) { volatile int *p; // volatile 33 p = const_cast<volatile int*>(in1); *p = 33; // volatile 55 const_cast<volatile int&>(in2) = 55; } int main() { int x=3,y=5; std::cout<<x<<" "<<y<<std::endl; // test_func_X(&x,y); std::cout<<x<<" "<<y<<std::endl; x=3; y=5; // test_func_Y(&x,y);//!!! std::cout<<x<<" "<<y<<std::endl; // volatile test_func_Z(&x,y); std::cout<<x<<" "<<y<<std::endl; x=3; y=5; std::cout<<x<<" "<<y<<std::endl; // volatile test_func_A(&x,y); std::cout<<x<<" "<<y<<std::endl; system("pause"); return 0; }
ユーザー5nwからの追加例
例を表示
#include <iostream> using namespace std; void f(int *x) { cout << __PRETTY_FUNCTION__ << endl; } void f(const int *x) { cout << __PRETTY_FUNCTION__ << endl; } int main() { int x = 5; int *px = &x; f(px); f(const_cast<const int*>(px)); return 0; }
constおよびvolatile修飾子は、const_castキャストおよび型キャスト演算子を使用してのみ削除または追加できます他のキャストは、constおよびvolatile修飾子(reinterpret_cast、static_cast、dynamic_cast)には影響しません。
reinterpret_cast
reinterpret_castキャスト演算子は、互換性のない型をキャストするために使用されます。 整数をポインターに、整数をポインターに、ポインターをポインターにキャストできます(リンクについても同様です)。 違いは、reinterpret_castがconstおよびvolatile修飾子を削除できず、ポインターではなく値による直接の安全でない型キャストもできないことです。 たとえば、reinterpret_castを使用してint変数をdouble変数にキャストすることはできません。
キャストの一般的なビュー:
reinterpret_cast <new_type>(exp)
例を表示
#include <iostream> // // struct AAA{ }; struct BBB{ }; // BBB struct BBB_X:BBB{ }; struct BBB_Y:BBB{ }; int main() { // int i = 5; double d = 111.222; char c = 'a'; int* pi = &i; double * pd = &d; const int* cpi = &i; void* v = NULL; // AAA A; BBB B; BBB_X BX; BBB_Y BY; // AAA* pA = &A; BBB* pB = &B; BBB_X* pBX = &BX; BBB_Y* pBY = &BY; // double int i = reinterpret_cast<int>(d);//!!! // /d = reinterpret_cast<int>(i);//!!! // int char c = reinterpret_cast<char>(pi); //char void v = reinterpret_cast<void*>(c); // void int pi = reinterpret_cast<int*>(v); // const int* pi = reinterpret_cast<int *>(cpi);//!!! // AAA BBB // pA = reinterpret_cast<AAA*>(pB); // double double d = reinterpret_cast<double>(pd);//!!! // ? pd = reinterpret_cast<double*>(d0;//!!! // pB = reinterpret_cast<BBB*>(pBX); pBY = reinterpret_cast<BBB_Y*>(pB); return 0; }
static_cast
static_castキャスト演算子は、プログラムのコンパイル段階で非多態型キャストに使用されます。 C言語スタイルのstatic_castとtypecastingの違いは、このキャスト演算子が値へのポインターのキャストまたはその逆などの無効な変換を追跡できることです(unsigned intはdoubleへのポインターにはなりません)。また、異なるタイプのポインターと参照のキャストが考慮されます同じクラス継承階層を上または下にキャストしている場合、またはvoidへのポインタである場合にのみ修正します。 これらの制限からの逸脱を修正する場合、プログラムのコンパイル時にエラーが生成されます。 多重継承を使用すると、static_castはソースオブジェクトではなく、サブオブジェクトへのポインターを返すことができます。
キャストの一般的なビュー:
static _cast <new_type>(exp)
例を表示
#include <iostream> // // struct AAA{ }; struct BBB{ }; // BBB struct BBB_X:BBB{ }; struct BBB_Y:BBB{ }; int main() { // int i = 5; double d = 111.222; char c = 'a'; int* pi = &i; double * pd = &d; const int* cpi = &i; void* v = NULL; // AAA A; BBB B; BBB_X BX; BBB_Y BY; // AAA* pA = &A; BBB* pB = &B; BBB_X* pBX = &BX; BBB_Y* pBY = &BY; // double int i = static_cast<int>(d); // d = static_cast<int>(i); // int char c = static_cast<char>(pi);//!!! //char void v = static_cast<void*>(c);//!!! // void int pi = static_cast<int*>(v); // const int* pi = static_cast<int *>(cpi);//!!! // AAA BBB // pA = static_cast<AAA*>(pB);//!!! // double double d = static_cast<double>(pd);//!!! // ? pd = static_cast<double*>(d0);//!!! // pB = static_cast<BBB*>(pBX); pBY = static_cast<BBB_Y*>(pB); return 0; }
dynamic_cast
dynamic_castキャスト演算子は、プログラム実行段階でのポリモーフィック型のキャストに使用されます(クラスに少なくとも1つの仮想関数がある場合、クラスはポリモーフィックと見なされます)。 キャストされるポインターが、結果のクラスのオブジェクトまたは結果から派生したクラスのオブジェクトを参照する場合、キャストは成功したと見なされます。 リンクについても同じです。 キャストが不可能な場合、ポインターが指定されると、プログラムの実行時にNULLが返されます。 リンクに対してキャストが実行されると、例外std :: bad_castがスローされます。 dynamic_castは、継承階層に従ってポリモーフィック型をキャストするように設計されているという事実にもかかわらず、階層の上の通常の非ポリモーフィック型に使用できます。 この場合、コンパイル段階でエラーを受け取ります。 dynamic_castキャスト演算子は、voidへのポインターにキャストしますが、voidへのポインターを別の型にキャストすることはできません。 ポリモーフィック型をキャストするdynamic_castの機能は、RTTI(実行時型識別)システムによって提供されます。これにより、プログラムの実行中にオブジェクトの型を識別できます。 多重継承を使用すると、dynamic_castは元のオブジェクトではなく、そのサブオブジェクトへのポインターを返すことができます。
キャストの一般的なビュー:
dynamic_cast <new_type>(exp)
例を表示
#include <iostream> // // struct AAA{ // virtual void do_some(){}; }; struct BBB{ // virtual void do_some(){}; }; // BBB struct BBB_X:BBB{ }; struct BBB_Y:BBB{ }; int main() { // void* v = NULL; // AAA A; BBB B; BBB_X BX; BBB_Y BY; // AAA* pA = &A; BBB* pB = &B; BBB_X* pBX = &BX; BBB_Y* pBY = &BY; // AAA BBB // pA = dynamic_cast<AAA*>(pB); if (pA == NULL) { std::cout<<"FAIL"<<std::endl;// !!! } // void BBB pB = dynamic_cast<AAA*>(v); // !!! // BBB void v = dynamic_cast<void*>(pB); // pB = dynamic_cast<BBB*>(pBX); pBY = dynamic_cast<BBB_Y*>(pB); if (pBY == NULL) { std::cout<<"FAIL"<<std::endl;// !!! } system("pause"); return 0; }
ソース:
プロジェクト講義のユージン・リンスキーによるビデオ講義
Alyona C ++ブログ
この投稿は@dreary_eyesです
完全なC ++リファレンスHerbert Schildt
「C ++言語の設計と進化」ビョルン・ストラウストルプ
ソース:
C ++言語標準(価格は212ドル)
C ++ N3337言語標準の無料のワーキングドラフト
オプション:
投稿@ SOLON7から撮影した画像