私の知る限り、ポインター/参照 static_cast の場合、この時点でクラス定義がコンパイラーに表示されない場合、 のstatic_cast
ように動作しますreinterpret_cast
。
static_cast
ポインタ/参照に対して安全ではなく、数値に対して安全なのはなぜですか?
私の知る限り、ポインター/参照 static_cast の場合、この時点でクラス定義がコンパイラーに表示されない場合、 のstatic_cast
ように動作しますreinterpret_cast
。
static_cast
ポインタ/参照に対して安全ではなく、数値に対して安全なのはなぜですか?
要するに、多重継承のためです。
長文:
#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_cast
to と fromで安全でないことを行うことができvoid*
ます。