C++ 来自“void *”的 dynamic_cast
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4131091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
dynamic_cast from "void *"
提问by dimba
According to this, void*
has no RTTI information, therefore casting from void*
is not legal and it make sense.
根据这个,void*
没有RTTI信息,因此从铸造void*
是不合法的,它是有意义的。
If I remember correctly, dynamic_cast
from void*
was working on gcc.
如果我没记错的话,dynamic_cast
fromvoid*
正在开发 gcc。
Can you please clarify the issue.
你能澄清一下这个问题吗?
回答by vitaut
dynamic_cast
works only on polymorphic types, i.e. classes containing virtual functions.
dynamic_cast
仅适用于多态类型,即包含虚函数的类。
In gcc you can dynamic_cast
tovoid*
but not from:
在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
}
回答by Tony Delroy
In 5.2.7 - Dynamic cast [expr.dynamic.cast]
it says that for dynamic_cast<T>(v)
:
在5.2.7 - Dynamic cast [expr.dynamic.cast]
它说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)
- 如果
T
是指针类型,v
则应是指向完整类类型的指针的右值 - 如果
T
是引用类型,v
则应是完整类类型的左值(感谢 usta 评论我的遗漏)
...
...
- Otherwise,
v
shall be a pointer to or an lvalue of a polymorphic type
- 否则,
v
应为指向多态类型的指针或左值
So, no, a (void*)
valueis not allowed.
所以,不,一个(void*)
值是不允许的。
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.
让我们考虑一下您的请求可能意味着什么:假设您有一个真正指向 a 的指针Derived1*
,但代码dynamic_cast
只知道它是 a void*
。假设您试图将其强制转换为 a 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
(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.)
(有些答案谈到需要将您从其转换为具有虚函数的多态类型的指针。这都是有效的,但有点误导。正如您在上面看到的,即使void*
是这样的类型它如果没有完整的类型信息,仍然无法可靠地工作,因为真正的问题void*
可能是指向派生对象的开始,而您需要一个指向基类子对象的指针,该基类子对象是从该基类子对象派生的。 )
回答by Motti
It is true that void*
can't be dynamically_cast
ed from.
确实void*
不能dynamically_cast
从。
You are probably mis-remembering. With g++ 4.5 and the following code
你可能记错了。使用 g++ 4.5 和以下代码
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)
不能 dynamic_cast 'p'(类型为 'void*')到类型 'struct A*' (源不是指向类的指针)
回答by sharptooth
I guess you confuse with dynamic_cast
tovoid*
. That is legal and obtains the pointer to the most derived class object.
我猜你和dynamic_cast
to混淆了void*
。这是合法的,并获得指向最派生类对象的指针。
dynamic_cast
fromvoid*
is illegal - the type casted from must be polymorphic - contain at least one virtual function (virtual destructor counts too).
dynamic_cast
fromvoid*
是非法的 - 类型转换必须是多态的 - 至少包含一个虚函数(虚析构函数也算在内)。
回答by Nathan Chappell
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."
为了补充托尼的好答案,这个小代码片段出于某种原因对我有帮助。首先,我们建立一个简单的层次结构。然后,我们看看是否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)))));
}
回答by usta
You can cast a pointer to polymorphic type to void *
, but not vice versa.
您可以将指向多态类型的指针强制转换为void *
,但反之则不行。