この質問は、ここのコメントに触発されています。
次のコード スニペットを検討してください。
struct X {}; // no virtual members
struct Y : X {}; // may or may not have virtual members, doesn't matter
Y* func(X* x) { return dynamic_cast<Y*>(x); }
何人かの人々は、コンパイラが の本体を拒否するだろうと提案しましたfunc。
ただし、これが標準で定義されているかどうかは、の実行時の値に依存するようですx。セクション 5.2.7 ( [expr.dynamic.cast]) から:
式の結果は、式を type
dynamic_cast<T>(v)に変換した結果です。完全なクラス型へのポインタまたは参照、または「cvへのポインタ」でなければなりません。演算子は constness をキャストしてはなりません。vTTvoiddynamic_cast
Tがポインタ型である場合は、v完全なクラス型へのポインタの prvalue であり、結果は type の prvalue ですT。Tが左辺値参照型である場合v、 は完全なクラス型の左辺値であり、結果は によって参照される型の左辺値になりTます。Tが右辺値参照型である場合v、 は完全なクラス型を持つ式であり、結果は によって参照される型の xvalue になりTます。の型が
vと同じか、 のクラス オブジェクト型が のクラス オブジェクト型よりも cv 修飾されていることを除いてTと同じである場合、結果は(必要に応じて変換されます) になります。TTvvの値が
vポインター ケースの null ポインター値である場合、結果は type の null ポインター値になりますT。T が「cv1 へのポインタ」であり、 の基底クラスである「cv2へのポインタ」型
Bを持つ場合、結果は が指すオブジェクトの一意のサブオブジェクトへのポインタになります。同様に、T が「cv1への参照」の場合であり、 の基底クラスである型cv2を 持つ場合、結果は によって参照されるオブジェクトの一意のサブオブジェクトになります. 結果は が左辺値参照の場合は左辺値、 が右辺値参照の場合は xvalue です. ポインタとcv2の場合、プログラムの形式が正しくありません。vDBDBDvBvDBDBDvTTがcv1よりも大きな cv-qualification を持っているか、Bがアクセスできないかあいまいな の基本クラスである場合D。それ以外の場合
vは、多相型へのポインターまたは左辺値でなければなりません。
Tが「cv へのポインター」である場合void、結果は が指す最も派生したオブジェクトへのポインターになりますv。それ以外の場合は、 が指し示すまたは参照するオブジェクトを が指すまたは参照vする型に変換できるかどうかを確認するために、ランタイム チェックが適用されTます。これらは無視されます。vB
Cがポイントまたは参照先のクラス型である場合T、実行時チェックは次のように論理的に実行されます。
が指す (参照する) 最も派生したオブジェクトで、オブジェクトの基底クラス サブオブジェクトを指す (参照する) 場合
v、および結果ポイント (参照する) が指す (参照する) サブオブジェクトからタイプのオブジェクトが 1 つだけ派生する場合) そのオブジェクトに。vpublicCCvCそれ以外の場合、が最も派生したオブジェクトの基底クラス サブオブジェクト
vを指し (参照し)public、最も派生したオブジェクトの型が型 の基底クラスを持ちC、それが明確であり、 である場合、結果は の サブオブジェクトをpublic指します (参照します) 。C最も派生したオブジェクト。それ以外の場合、ランタイム チェック は失敗します。
ポインター型への失敗したキャストの値は、必要な結果型の null ポインター値です。参照型へのキャストが失敗すると、 がスローされ
std::bad_castます。
私がこれを読んだ方法では、ポリモーフィック型の要件は、上記の条件のいずれも満たされていない場合にのみ適用され、それらの条件の 1 つが実行時の値に依存します。
もちろん、いくつかのケースでは、コンパイラーは、入力が適切に NULL ではないことを積極的に判断できます (たとえば、thisポインターの場合)。ただし、ステートメントに到達すると判断できない限り、コンパイラーはコードを拒否できないと思います。 (通常は実行時の質問)。
もちろん、ここでは警告診断が重要ですが、コンパイラがこのコードをエラーで拒否するのは標準に準拠していますか?