次の例を検討してください。
class Base {
public:
int data_;
};
class Derived : public Base {
public:
void fun() { ::std::cout << "Hi, I'm " << this << ::std::endl; }
};
int main() {
Base base;
Derived *derived = static_cast<Derived*>(&base); // Undefined behavior!
derived->fun();
return 0;
}
C++ 標準によると、関数呼び出しは明らかに未定義の動作です。しかし、利用可能なすべてのマシンとコンパイラ (VC2005/2008、RH Linux および SunOS の gcc) では、期待どおりに動作します ("Hi!" が出力されます)。このコードが正しく動作しない構成を知っている人はいますか? それとも、同じ考えを持つより複雑な例かもしれません (とにかく、Derived は追加のデータを運ぶべきではないことに注意してください)?
アップデート:
標準 5.2.9/8 から:
タイプ「cv1 B へのポインター」の右辺値 (B はクラス タイプ) は、タイプ「cv2 D へのポインター」の右辺値に変換できます。ここで、D は B から派生したクラス (第 10 節) です。 「D へのポインター」から「B へのポインター」への変換が存在し (4.10)、cv2 が cv1 と同じ cvqualification であるか、cv1 より大きい cvqualification であり、B が D の仮想基底クラスではない。null ポインター値 (4.10)変換先の型の null ポインター値に変換されます。型「cv1 B へのポインター」の右辺値が実際には型 D のオブジェクトのサブオブジェクトである B を指している場合、結果のポインターは型 D の外側のオブジェクトを指します。それ以外の場合、キャストの結果は未定義です。
そしてもう1つ9.3.1(@Agent_Lに感謝):
クラス X の非静的メンバー関数が、型 X または X から派生した型ではないオブジェクトに対して呼び出された場合、動作は未定義です。
ありがとう、マイク。