答案 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 *
,但反之亦然。