キャストとは
キャストとは、型変換のことであり、C++のキャストには目的や用途が異なる複数のキャストが用意されています。
キャストは、以下のような場面で重要な役割を果たします。
- データ型の一致
-
関数呼び出しや演算において、データ型が一致しない場合に型を一致させます。
- 継承関係のあるクラス
-
基底クラスと派生クラス間でポインタや参照を変換します。
- APIの使用
-
特定のライブラリやAPIが異なるデータ型を必要とする場合に、その型に変換します。
キャストには暗黙的キャストと明示的キャストがあります。
暗黙的キャスト(Implicit Cast)
int i = 42;
double d = i;
double d = i;
の部分で暗黙的キャストが行われ、int
型で定義したi
はdouble
型に変換されます。暗黙的キャストは、コンパイラが自動的に行う型変換です。プログラマが明示的に型変換を指示しなくても、必要に応じてコンパイラが適切な型変換を行います。暗黙的キャストは、安全と判断される場合にのみ行われます。
明示的キャスト(Explicit Cast)
int i = 42;
double d = (double)i;
double d2 = static_cast<double>(i);
このような書き方が明示的キャストです。double d = (double)i;
とdouble d2 = static_cast(i);
はどちらもint
型で定義されたi
を明示的にdouble
型にキャストする例ですが、double d = (double)i;
の方はC言語スタイルのキャストです。C++ではdouble d2 = static_cast(i);
と書くのが一般的です。
明示的キャストは、プログラマが特定の型変換を明示的に指示する場合に使用されます。暗黙的キャストでは行われない型変換も可能ですが、型安全性が保証されない場合もあるため、誤用に注意が必要です。
この記事では、C++で提供されている主要な4種類の明示的キャストについて説明していきます。
static_cast
int i = 10;
double d = static_cast<double>(i);
用途
- 基本データ型間の変換
- クラス間の変換(明示的に定義された変換)
- ポインタや参照の型変換
- 数値型や列挙型などの変換
注意点
- コンパイル時にチェックされるが、実行時のチェックは行われない
- 不正なキャストをすると未定義動作になる可能性がある
- 継承関係のあるクラス間の安全なキャストには使えるが、ポリモーフィズム(仮想関数)が関係する場合は
dynamic_cast
を使うべき
dynamic_cast
class Base { virtual void func() {} };
class Derived : public Base {};
Base* b = new Derived();
Derived* d = dynamic_cast<Derived*>(b);
用途
- ポインタや参照のダウンキャスト(基底クラスから派生クラスへのキャスト)
- 安全なランタイム型情報を利用したキャスト
- ポリモーフィズム(仮想関数)を持つクラスに対して使用
注意点
- クラスに仮想関数が存在しないと使用できない
- キャストに失敗するとポインタの場合は
nullptr
を返し、参照の場合はstd::bad_cast
例外を投げる - 実行時のオーバーヘッドがある
const_cast
const int a = 10;
int* p = const_cast<int*>(&a);
用途
- オブジェクトの定数性を変更する(
const
修飾子の追加や削除) - メンバー関数内での
const
修飾子の変更
注意点
- 変更したオブジェクトを不正に書き換えると未定義動作になる
- もともと定数でないオブジェクトに対して使用するべき
reinterpret_cast
int i = 65;
char* c = reinterpret_cast<char*>(&i);
用途
- ポインタ型の再解釈(異なるポインタ型への変換)
- 任意の型間のビット単位の再解釈
- ハードウェアや低レベルプログラミングでの特殊用途
注意点
- 非常に危険で、使い方を誤ると未定義動作になる可能性が高い
- 型安全性が全く保証されないため、使用する場面をよく考える必要がある
さいごに
今回はキャストの概要と注意点、C++で提供されているキャストについて紹介しました。キャストはバグの原因になることも多いですが、使いこなせば強力なツールになります。