クラスベースのプログラミングでは、ダウンキャスト、または型リファインメントとは、基底クラスまたは親クラスの参照を、より制限された派生クラスの参照にキャストする行為です。[ 1 ]これは、オブジェクトが既に派生クラスのインスタンスである場合にのみ許可されるため、この変換は本質的に誤りやすいものです。対照的に、オブジェクトをそのスーパークラスのインスタンスであるかのように明示的に扱うアップキャストは、常に可能です。[ 2 ]
多くの環境では、型イントロスペクションを使用して実行時にオブジェクト インスタンスの型を取得し、その結果を使用して別の型との型の互換性を明示的に評価できます。多相型を比較した場合の結果は、同等(同一)または無関係(非互換性)であることに加えて、次の 2 つのケースがあります。つまり、最初の型が 2 番目の型から派生している場合、そして同じものが逆の順序で入れ替わっている場合です(サブタイピング § サブサンプションを参照)。
この情報があれば、プログラムは、オブジェクトを型付き変数に格納するなどの操作を実行する前に、その操作が型安全かどうか、あるいはエラーが発生するかどうかをテストできます。実行時インスタンスの型がターゲット変数(つまり親)の型(の子)から派生している場合、ダウンキャストが可能です。
public class Fruit {} // 親クラスpublic class Apple extends Fruit {} // 子クラスpublic static void main ( String [] args ) { // 以下は暗黙的なアップキャストです。Fruit parent = new Apple (); // 以下はダウンキャストです。ここでは、変数 `parent` がApple のインスタンスを保持しているため、正しく動作します。Apple child = ( Apple ) parent ; }// 親クラス: class Fruit { public : // 実行時チェックの動的キャストを使用するには、ポリモーフィックである必要があります。virtual ~ Fruit () = default ; };// 子クラス: class Apple : public Fruit {};int main ( int argc , char * argv []) { // 以下は暗黙的なアップキャストです。Fruit * parent = new Apple (); // 以下はダウンキャストです。ここでは、変数 `parent` がApple のインスタンスを保持しているため、正しく動作します。Apple * child = dynamic_cast < Apple *> ( parent ); delete parent ; }ダウンキャストは、Parent変数によって参照される値の型が既知の場合に便利で、値をパラメータとして渡す際によく使用されます。以下の例では、objectToStringメソッドはObject型のパラメータを受け取りますが、これはString型であると想定されています。
public static String objectToString ( Object myObject ) { // これは、myObject が現在保持している値が文字列の場合にのみ機能します。return ( String ) myObject ; }public static void main ( String [] args ) { // String を渡したので、myObject の値は String になります。String result = objectToString ( "My String" ); Object iFail = new Object (); // String の値を持たない Object を渡したので、これは失敗します。result = objectToString ( iFail ); }このアプローチでは、ダウンキャストによってコンパイラが潜在的なエラーを検出できなくなり、代わりに実行時エラーが発生します。myObject を String にダウンキャスト ('(String)myObject') することはコンパイル時には不可能でした。myObject が String 型になる場合があるため、渡されたパラメータが論理的かどうかは実行時にしか判断できません。また、汎用的な java.lang.Object.toString() を使用して myObject をコンパイル時の String に変換することもできますが、この方法では、不適切な場合や安全でない場合に toString() のデフォルト実装が呼び出されるリスクがあり、例外処理ではこれを防ぐことができません。
C++では、実行時の型チェックはdynamic_castによって実装されます。コンパイル時のダウンキャストはstatic_castによって実装されますが、この操作では型チェックは行われません。不適切に使用すると、未定義の動作を引き起こす可能性があります。
設計が不十分な例としてよく挙げられるのが、Javaのジェネリクスが導入される以前のJavaコンテナのような、上位型のコンテナです。これは、格納されているオブジェクトを再利用するために、ダウンキャストする必要があるというものです。