web-dev-qa-db-ja.com

「void *」からのdynamic_cast

this によると、void*にはRTTI情報がないため、void*からのキャストは不正であり、意味があります。

私の記憶が正しければ、dynamic_castvoid*がgccで作業していた。

問題を明確にしていただけませんか。

35
dimba

dynamic_castは、ポリモーフィック型、つまり仮想関数を含むクラスでのみ機能します。

Gccではdynamic_casttovoid*ではなくfrom

struct S
{
    virtual ~S() {}
};

int main()
{
    S* p = new S();
    void* v = dynamic_cast<void*>(p);
    S* p1 = dynamic_cast<S*>(v); // gives an error
}
43
vitaut

_5.2.7 - Dynamic cast [expr.dynamic.cast]_では、dynamic_cast<T>(v)の場合は次のようになります。

  • Tがポインター型の場合、vは完全なクラス型へのポインターの右辺値になります
  • Tが参照型の場合、vは完全なクラス型の左辺値になります(欠落しているthisについてコメントしてくれたustaに感謝)

...

  • それ以外の場合、vは多相型へのポインタまたは左辺値になります

したがって、いいえ、_(void*)_ valueは使用できません。

あなたのリクエストが何を意味するのか考えてみましょう:_Derived1*_へのポインターを持っているとしますが、コード_dynamic_cast_- ingはそれが_void*_であることだけを知っています。それを_Derived2*_にキャストしようとしているとしましょう。ここで、両方の派生クラスは共通のベースを持っています。表面的には、すべてのポインタが関連する仮想ディスパッチテーブルとRTTIへのポインタを含む同じBaseオブジェクトを指していると考えるかもしれません。ただし、派生クラスには複数の基本クラスが含まれる可能性があるため、必要なBaseクラスサブオブジェクトは、_Derived*_-_void*_としてのみ使用可能なオブジェクトではない可能性があることを考慮してください指しています。それはうまくいきません。結論:コンパイラーは、関係する型に基づいてポインターを調整できるように、これらの型を知る必要があります。

 Derived1 * -----> [AnotherBase] 
 [[VDT] Base] <-ですが、
 [追加メンバー]の開始へのポインターが必要ですdynamic_cast 
のオブジェクト

(一部の回答は、キャスト元のポインターが仮想関数を持つ多相型である必要があることを述べています。これはすべて有効ですが、少し誤解を招きます。上記のように、_void*_が実際の問題は、_void*_がおそらく派生オブジェクトの開始を指しているのに対し、基本クラスのサブオブジェクトへのポインターが必要であるため、完全な型情報がないと、そのような型にはまだ確実に機能しません。キャスト先の型の派生元のオブジェクト。)

17
Tony Delroy

void*dynamically_castで作成することはできません。

あなたはおそらく覚えていません。 g ++ 4.5と次のコード

struct A {
    virtual ~A();
};

int main() {
    A a;
    void *p = &a;
    A* pa = dynamic_cast<A*>(p);
}

次のエラーが発生します。

dynamic_cast 'p'(タイプ 'void *')からタイプ 'struct A *'にできません(ソースはクラスへのポインターではありません)

4
Motti

dynamic_casttovoid*と混同していると思います。これは正当であり、最も派生したクラスオブジェクトへのポインタを取得します。

dynamic_castfromvoid*は不正です-キャスト元の型はポリモーフィックでなければなりません-少なくとも1つの仮想関数が含まれています(仮想デストラクタもカウントされます)。

1
sharptooth

トニーのニースの答えに追加するために、この小さなコードスニペットは、何らかの理由で私に役立ちます。まず、単純な階層を確立します。次に、dynamic_castは「存続」できますstatic_cast。この実験の前に、「実行時の型情報があるので、動的キャストはそれを理解する必要がある」と思いました。今私は「dynamic_castは、コンパイラが認識しているいくつかのテーブルに基づいてその情報を検索する必要があるため、魔法のような力を持つことはできません。 "

#include <iostream>
#include <cassert>

using namespace std;

class A {
  protected:
  virtual void foo() { cout << "A" << endl; }
};

class B1 : public A {
  private:
  virtual void foo() override { cout << "B1" << endl; }
};

class B2 : public A {
  public:
  virtual void foo() override { cout << "B2" << endl; }
};

int main(int argc, char **argv) {
  B1 b1;
  // undefined behavior even though dynamic_cast didn't return null
  dynamic_cast<B2*>(
      static_cast<B2*>(
        static_cast<A*>(&b1)))->foo();
  // dynamic_cast returns null here though
  assert (!dynamic_cast<B2*>
          (static_cast<A*>
           (static_cast<B2*>
            (static_cast<A*>(&b1)))));
}
1
Nathan Chappell

ポリモーフィック型へのポインターをvoid *にキャストできますが、その逆はできません。

0
usta