14

私の知る限り、ポインター/参照 static_cast の場合、この時点でクラス定義がコンパイラーに表示されない場合、 のstatic_castように動作しますreinterpret_cast

static_castポインタ/参照に対して安全ではなく、数値に対して安全なのはなぜですか?

4

2 に答える 2

24

要するに、多重継承のためです。

長文:

#include <iostream>

struct A { int a; };
struct B { int b; };
struct C : A, B { int c; };

int main() {
    C c;
    std::cout << "C is at : " << (void*)(&c) << "\n";
    std::cout << "B is at : " << (void*)static_cast<B*>(&c) << "\n";
    std::cout << "A is at : " << (void*)static_cast<A*>(&c) << "\n";

}

出力:

C is at : 0x22ccd0
B is at : 0x22ccd4
A is at : 0x22ccd0

B* に正しく変換するには、static_cast でポインター値を変更する必要があることに注意してください。コンパイラが C のクラス定義を持っていなければ、B が基本クラスであることを認識できず、どのオフセットを適用すべきかを確実に認識できません。

しかし、定義が見えない状況では、 static_cast は reinterpret_cast のように動作せず、禁止されています:

struct D;
struct E;

int main() {
    E *p1 = 0;
    D *p2 = static_cast<D*>(p1); // doesn't compile
    D *p3 = reinterpret_cast<D*>(p1); // compiles, but isn't very useful
}

単純な C スタイルのキャスト(B*)(&c)は、あなたの言うとおりです。構造体 C の定義が表示され、B が基本クラスであることを示している場合、それは static_cast と同じです。型が前方宣言のみの場合は、reinterpret_cast と同じです。これは、C と互換性があるように設計されているためです。つまり、C で可能な場合に C が行うことを行う必要があります。

static_cast は、組み込み型に対して何をすべきかを常に知っています。これが組み込み型の意味です。int を float などに変換できます。そのため、数値型に対しては常に安全ですが、(a) ポインターが何を指しているかを認識しており、(b) ポインターが指す型の間に正しい種類の関係がない限り、ポインターを変換できません。したがって、 に変換できますが、 には変換できintませfloatん。int*float*

AndreyT が言うように、安全でない方法で使用できる方法がありstatic_cast、コードが合法であるため、コンパイラはおそらくあなたを救わないでしょう:

A a;
C *cp = static_cast<C*>(&a); // compiles, undefined behaviour

できることの 1 つはstatic_cast、派生クラスへのポインターを「ダウンキャスト」することです (この場合、C は A の派生クラスです)。しかし、参照先が実際には派生クラスのものでない場合、あなたは運命づけられています。Aは実行時にチェックを実行しますが、私の例のクラス Cでは、 A には仮想関数がないためdynamic_cast、 a を使用できません。dynamic_cast

同様に、static_castto と fromで安全でないことを行うことができvoid*ます。

于 2010-03-04T19:31:06.323 に答える