14

私は、何かがどのタイプであるかを知っている状況にいることに気づきました。Type は、3 つ (またはそれ以上) の継承レベルの 1 つです。私は返す factory を呼び出しますB*が、T は型の最高レベル (私のコードがそれが何であるかを知っている場合) または 2 番目のレベルのいずれかです。

とにかく、私はstatic_cast間違ったことをテンプレートで行いました。私の質問は、安全に静的キャストできるのはいつですか? そんな時ってありますか?この場合、動的キャストが無視する (そして null を返す) 奇抜なものとして T を誤って持っていると、むしろコンパイル エラーが発生するので、この場合に実行しました。ただし、正しい型がわかっている場合、ポインターが調整されないため、ポインターが正しくありません。この場合、静的キャストが許可される理由がまったくわかりません。

ダウン キャストに static_cast を安全に使用できるのはいつですか? 状況はありますか?今では、 a を使用するのは常に間違っているようですstatic_cast(目的がダウンキャストである場合)

わかりました、それを再現する方法を見つけました。

#include <iostream>
struct B { virtual void f1(){} };
struct D1 : B {int a;};
struct D2 : B {int a, b; };
struct DD : D1, D2 {};

int main(){
void* cptr = new DD(); //i pass it through a C interface :(
B*  a = (B*)cptr;
D2* b = static_cast<D2*>(a); //incorrect ptr
D2* c = dynamic_cast<D2*>(a); //correct ptr
std::cout << a << " " <<b << " " <<c;
}
4

6 に答える 6

13

クロスキャスト:

struct Base1 { virtual void f1(); };
struct Base2 { virtual void f2(); };
struct Derived : Base1, Base2 {};

Base1* b1 = new Derived();
Base2* b2 = dynamic_cast<Base2*>(b1);

を使用する必要がありますがdynamic_cast、これを行うことはできませんstatic_cast(static_castコンパイル時エラーが発生するはずでした)。 dynamic_castいずれかの基本クラスが多態的でない場合にも失敗します (仮想関数の存在はオプションではありません)。

MSDN でこの説明を参照してください

于 2011-10-17T04:44:19.170 に答える
5

public (またはアクセス可能な) 基本クラスとしてあり、タイプがDerivedである場合、 はアップキャストです。BasedDerived*static_cast<Base*>(d)

これは常に技術的に安全です。

また、メソッドを非表示 (シャドーイング) にしている場合を除いて、通常は不要です。

乾杯 & hth.,

于 2011-10-17T04:23:10.277 に答える
3

問題は次の行にあります。

B*  a = (B*)cptr;

何かを void ポインターに変換する場合は、他のキャストを行う前に、最初に変換したときと同じ型に戻す必要があります。複数の異なる型のオブジェクトが同じ void ポインターを通過する必要がある場合は、void ポインターに変換する前に、まず共通の型にキャストする必要があります。

int main(){
  B *bptr = new DD; // convert to common base first (won't compile in this case)
  void* cptr = bptr; // now pass it around as a void pointer
  B*  a = (B*)cptr; // now back to the type it was converted from
  D2* b = static_cast<D2*>(a); // this should be ok now
  D2* c = dynamic_cast<D2*>(a);  // as well as this
  std::cout << a << " " <<b << " " <<c;
}

編集: キャスト時に cptr が B から派生した型のオブジェクトを指していることだけを知っている場合、それでは続行するのに十分な情報ではありません。コンパイラは、DD ポインターを B ポインターに変換しようとすると、そのことを知らせます。

あなたがしなければならないことは、次のようなものです:

int main(){
  void* cptr = new DD; // convert to void *
  DD* a = (DD*)cptr; // now back to the type it was converted from
  D2* b = static_cast<D2*>(a); // this should be ok now, but the cast is unnecessary
  D2* c = dynamic_cast<D2*>(a);  // as well as this
  std::cout << a << " " <<b << " " <<c;
}

しかし、実際の使用でそれが許容できるかどうかはわかりません。

于 2011-10-17T05:09:52.280 に答える
2

オブジェクトが実際にそのクラスのインスタンスであることが確実な場合は、安全にアップキャストできます。

class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};

int main()
{
    Base* b = new Derived1;

    Derived1* d1 = static_cast<Derived1*>(b); // OK
    Derived2* d2 = static_cast<Derived2*>(b); // Run-time error - d isn't an instance of Derived2
}
于 2011-10-17T04:23:50.173 に答える