来自“void *”的dynamic_cast

时间:2010-11-09 06:36:38

标签: c++ rtti void-pointers dynamic-cast

根据thisvoid*没有RTTI信息,因此从void*投射不合法且有意义。

如果我没记错的话,来自dynamic_cast的{​​{1}}正在使用gcc。

请你澄清一下这个问题。

6 个答案:

答案 0 :(得分:42)

dynamic_cast仅适用于多态类型,即包含虚函数的类。

在gcc中,您可以dynamic_cast void*但不能来自

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
}

答案 1 :(得分:16)

5.2.7 - Dynamic cast [expr.dynamic.cast]中,它代表dynamic_cast<T>(v)

  • 如果T是指针类型,v应该是指向完成类类型的指针的右值
  • 如果T是引用类型,v应该是完整类类型的左值(感谢usta评论我错过了这个)

...

  • 否则,v应为多态类型的指针或左值

所以,不,不允许(void*)

让我们考虑一下你的请求可能意味着什么:说你有一个真正指向Derived1*的指针,但代码dynamic_cast只知道它是void*。假设您正在尝试将其转换为Derived2*,其中两个派生类都有一个共同的基础。从表面上看,您可能认为所有指针都指向相同的Base对象,该对象包含指向相关虚拟调度表和RTTI的指针,因此所有内容都可以挂起。但是,请考虑派生类可能有多个基类,因此所需的Base类子对象可能不是Derived* - 仅可用作void* - 的子对象。指点。它不会起作用。结论:编译器需要知道这些类型,以便它可以根据所涉及的类型对指针进行一些调整。

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

(有些答案谈论你需要将指针转换成具有虚函数的多态类型。这一切都是有效的,但有点误导。如上所述,即使{{1对于这样的类型,如果没有完整的类型信息,它仍然无法可靠地工作,因为真正的问题是void*可能指向派生对象的开始,而你需要一个指向基础的指针转换类型派生的类子对象。)

答案 2 :(得分:4)

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 *'(source不是指向类的指针)

答案 3 :(得分:1)

我猜您与dynamic_cast 混淆了 void*。这是合法的,并获得指向派生程度最高的类对象的指针。

来自 dynamic_cast

void* 是非法的 - 从中​​输入的类型必须是多态的 - 至少包含一个虚函数(虚拟析构函数也计算在内)。

答案 4 :(得分:1)

要添加到Tony的漂亮答案中,此小代码段出于某种原因对我有所帮助。首先,我们建立一个简单的层次结构。然后,我们查看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)))));
}

答案 5 :(得分:0)

您可以将指向多态类型的指针强制转换为void *,但反之亦然。