15

次のコードが未定義の動作につながるかどうか疑問に思っています:

#include <cstddef>
#include <cstdio>

struct IA { 
  virtual ~IA() {}
  int a = 0;
};
struct IB {
  virtual ~IB() {}
  int b = 0;
};
struct C: IA, IB {};

int main() {
  C* pc = nullptr;
  IB* pib = pc;
  std::printf("%p %p", (void*)pc, (void*)pib);
}
4

2 に答える 2

9

null ポインターのアップキャストは、別の null ポインターを提供するために明確に定義されています。

4.10p3:

「 cv へのポインター」D型( はクラス型) の prvalue は、 「cvへのポインター」型( は の基底クラス) のDprvalue に変換できます。... null ポインター値は、宛先型の null ポインター値に変換されます。 BBD

于 2015-04-24T15:02:31.290 に答える
8

Stroustrup は、1989 年の多重継承論文 [PDF] のセクション 4.5 でこのケースについて説明しています。

解決策は、ポインター値 0 をテストする変換 (キャスト) 操作を詳しく説明することです [...]

追加された複雑さと実行時のオーバーヘッドは、テストと増分です。

実装では、NULL 値を明示的にチェックし、キャストの結果が引き続き NULL 値であることを確認します。これは C++98 で当てはまり、C++11 およびnullptr.

これは、派生クラスから基底クラスの 1 つへのキャストでポインターの実際の値を変更する必要がある複数の基底クラスの場合に特に重要です。

Cあなたの例では、メモリ内のレイアウトには最初に のバイトが含まれIA、次にのバイトが含まれますIBIAの先頭へのポインタは の部分のC先頭も指すため、へのキャストは簡単です。一方、にキャストするには、ポインターを のサイズだけシフトする必要があります。nullptr の場合にこのシフトを実行すると、キャスト後に null 以外のポインターになるため、null の特別な処理が行われます。IACIBCIA

ascheplerで指摘されているように、標準の関連セクションは [conv.ptr] §4.10 です。

型「cv Dへのポインター」の prvalue はクラス型であり、型「 cvDへのポインター」の prvalue に変換できます。ここで、は の基本クラス [...] です。[...] 変換の結果は、派生クラス オブジェクトの基本クラス サブオブジェクトへのポインターです。null ポインター値は、変換先の型の null ポインター値に変換されます。 BBD

于 2015-04-24T15:02:27.157 に答える