C++ における必須の型変換には、主に static_cast、dynamic_cast、const_cast、reinterpret_cast の 4 つのタイプがあります。
1.静的キャスト
静的型変換の使用形式は次のとおりです。
static_cast<new_type> (expresion);
このうち、new_type はターゲットの型であり、expression は元のデータ型の変数または式です。
static_cast は、非 const オブジェクトを const オブジェクトに変換するなど、暗黙的な変換を強制するために使用され、コンパイル時にチェックされますが、変換の安全性を保証する実行時の型チェックはありません。主に以下のような用途があります。
- クラス階層内の基本クラスと派生クラス間のポインターまたは参照の変換に使用されます。現時点では、アップキャスト (つまり、派生クラスのポインターまたは参照を基本クラスの表現に変換する) を実行しても安全ですが、ダウンキャスト (基本クラスのポインターまたは参照を表現に変換する) を実行する場合は安全です。派生クラスの)、動的な型チェックがないため、安全ではありません。
- int から char、int から enum への変換など、基本的なデータ型間の変換に使用されます。この変換のセキュリティは開発者によって保証される必要があります。
- null ポインターをターゲット型のポインターに変換します (これは非常に安全ではありません)。
- 任意の型の式を void 型に変換します
- static_cast は、expression の const、volatile、__unaligned 属性を変換できません
例は次のとおりです。
char a = 'a';
int b = static_cast<int>(a);//正确,将char型数据转换成int型数据
double *c = new double;
void *d = static_cast<void*>(c);//正确,将double指针转换成void指针
int e = 10;
const int f = static_cast<const int>(e);//正确,将int型数据转换成const int型数据
const int g = 20;
int *h = static_cast<int*>(&g);//编译错误,static_cast不能转换掉g的const属性
2.ダイナミックキャスト
動的型変換の形式は次のとおりです。
dynamic_cast<type>(expression);
Dynamic_cast は、実行時に型変換が正当であるかどうかを確認します。アップリンク変換を実行する場合、dynamic_cast と static_cast に違いはなく、どちらも安全です。ダウンリンク変換中、dynamic_cast は変換の型を確認します。これは static_cast よりも安全です。
- 組み込みのプリミティブ データ型のキャストには使用できません
- Dynamic_cast 変換が成功すると、型へのポインタまたは参照が返されます。変換ターゲットの型がポインタで失敗した場合は NULL を返し、変換テンプレートの型が参照で失敗した場合は std::bad_cast 例外がスローされます
- クラス ポインターを変換するときは、基本クラスに仮想関数が必要です
なぜ基本クラスに仮想関数が必要なのでしょうか? Dynamic_cast 変換は実行時に実行され、実行時変換ではクラス オブジェクトの情報 (継承関係など) を知る必要があります。仮想関数テーブルは、実行時にこの情報を取得するのに役立ちます。C++ オブジェクト モデルでは、仮想関数テーブル ポインタはオブジェクト インスタンスの先頭にあり、派生クラスが継承するため、このポインタを通じて、親クラスを含むこのクラスのオブジェクトのすべての仮想関数を取得できます。基本クラスの仮想関数テーブル。オブジェクトに継承関係があるかどうかを判断するために使用できます。
例 1: 継承における変換
アップリンク変換では、dyanmic_cast は static_cast と同じくらい安全です。ダウンコンバート時
class A { virtual void f(){}; };
class B : public A{ };
void main()
{
A* pA = new B;
B* pB = dynamic_cast<B*>(pA);
}
クラス A には仮想関数が存在する必要があります。これは、dynamic_cast ランタイム型チェックには、クラスの仮想関数テーブルに格納されるランタイム型情報が必要であり、仮想関数を定義するクラスのみが仮想関数テーブルを持つためです。
例 2: void* 変換
場合によっては、ポインタを void* に変換し、必要に応じて void* をターゲット型ポインタに再変換する必要があります。
class A { virtual void f(){} };
int main()
{
A *pA = new A;
void *pV = dynamic_cast<void *>(pA);
}
例 3: ダイヤモンド継承におけるアップキャスト
class A { virtual void f() {}; };
class B :public A { void f() {}; };
class C :public A { void f() {}; };
class D :public B, public C { void f() {}; };
継承関係は次のとおりです。
この時点で、D オブジェクト ポインターを A 型のポインターに安全に変換できますか?
void main()
{
D *pD = new D;
A *pA = dynamic_cast<A *>(pD); // pA = NULL
}
結果はヌルポインタになります。これは、B と C の両方が仮想関数を実装しているため、変換を実行する際に変換パスを選択することができません。1 つの方法は、コンバージョン パスを指定することです。
void main()
{
D *pD = new D;
B *pB = dynamic_cast<B *>(pD);
A *pA = dynamic_cast<A *>(pB);
}
3.const_cast
これは主に、型の const、volatile、および __unligned 属性を削除するために使用されます。形式:
const_cast<type>(expression);
const ポインタは非 const ポインタに変換されても元のオブジェクトを指し、const 参照は非 const 参照に変換されても元のオブジェクトを参照します。
const char *pc;
char *p = const_cast<char*>(pc);
4.再解釈キャスト
次の形式の非常に積極的な型変換:
reinterpret<type>(expression);
type は、ポインター、参照、算術型、関数ポインター、またはメンバー ポインターである必要があります。ポインターを整数に変換することも、整数をポインターに変換することもできます (まずポインターを整数に変換し、次に整数を元の型のポインターに変換して、元のポインター値を取得します)。
Dynamic_cast は実行時にチェックされ、他の 3 つはコンパイル時に実行されます。