简体   繁体   中英

dynamic_cast from “void *”

According to this , void* has no RTTI information, therefore casting from void* is not legal and it make sense.

If I remember correctly, dynamic_cast from void* was working on gcc.

Can you please clarify the issue.

dynamic_cast works only on polymorphic types, ie classes containing virtual functions.

In gcc you can dynamic_cast to void* but not 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
}

In 5.2.7 - Dynamic cast [expr.dynamic.cast] it says that for dynamic_cast<T>(v) :

  • If T is a pointer type, v shall be an rvalue of a pointer to complete class type
  • If T is a reference type, v shall be an lvalue of a complete class type (thanks usta for commenting on my missing this)

...

  • Otherwise, v shall be a pointer to or an lvalue of a polymorphic type

So, no, a (void*) value is not allowed.

Let's think about what your request might mean: say you've got a pointer that's really to a Derived1* , but the code dynamic_cast -ing only knows it's a void* . Let's say you're trying to cast it to a Derived2* , where both derived classes have a common base. Superficially, you might think all the pointers would point to the same Base object, which would contain a pointer to the relevant virtual dispatch table and RTTI, so everything could hang together. But, consider that derived classes may have multiple base classes, and therefore the needed Base class sub-object might not be the one to which the Derived* - available only as a void* - is pointing. It wouldn't work. Conclusion: the compiler needs to know these types so it can perform some adjustment to the pointers based on the types involved.

Derived1* -----> [AnotherBase]
                 [[VDT]Base]    <-- but, need a pointer to start of
                 [extra members]    this sub-object for dynamic_cast

(Some answers talk about the need for the pointer you're casting from to be of a polymorphic type, having virtual functions. That's all valid, but a bit misleading. As you can see above, even if the void* is to such a type it still wouldn't work reliably without the full type information, as the real problem is that void* is presumably pointing to the start of the derived object, whereas you need a pointer to the base class sub-object from which the cast-to type derives.)

It is true that void* can't be dynamically_cast ed from.

You are probably mis-remembering. With g++ 4.5 and the following code

struct A {
    virtual ~A();
};

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

I get the following error:

cannot dynamic_cast 'p' (of type 'void*') to type 'struct A*' (source is not a pointer to class)

I guess you confuse with dynamic_cast to void* . That is legal and obtains the pointer to the most derived class object.

dynamic_cast from void* is illegal - the type casted from must be polymorphic - contain at least one virtual function (virtual destructor counts too).

To add to Tony's nice answer, this little code snippet helps me for some reason. First, we establish a simple hierarchy. Then, we see if dynamic_cast can "survive" a static_cast . Before this experiment I thought "the run time type information is there, dynamic cast should figure it out." Now I realize " dynamic_cast must have to look up its information based on some tables the compiler is aware of, so it can't have some magical power."

#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)))));
}

您可以将指向多态类型的指针转​​换为void * ,但反之则不然。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM