[英]How do I dynamically cast from a void * pointer generically?
class BASE {
public:
virtual ~BASE() {}
void lamp() {
cout << "\nBASE CLASS";
}
};
class DERIVED : public BASE {
public:
void fun();
};
void DERIVED::fun() {
cout << "\nDERIVED CLASS!";
}
int main() {
BASE * pbase = new DERIVED; //BASE CLASS POINTER
void * vbase = pbase; //VOID POINTER TAKING BASE POINTER
DERIVED * pder; //DERIVED CLASS POINTER
//pder = static_cast<DERIVED *>(vbase); //THIS WORKS
pder = dynamic_cast<DERIVED *>(vbase); //THIS DOESN'T
pder->lamp();
pder->fun();
return 0;
}
Whenever I try to dynamically cast the void*
pointer to the derived class pointer, I get the following error: 每当我尝试将
void*
指针动态转换为派生类指针时,都会出现以下错误:
cannot dynamic_cast 'vbase' (of type 'void*') to type 'class DERIVED*' (source is not a pointer to class)
无法dynamic_cast'vbase'(类型'void *')键入'class DERIVED *'(源不是指向class的指针)
I've searched StackOverflow and followed advice by implementing a virtual function in the base class to avoid the error. 我搜索了StackOverflow,并按照建议在基类中实现了一个虚函数,以避免出现错误。 What am I doing wrong?
我究竟做错了什么? Is this possible at all?
这有可能吗?
My overall intention is to cast ANY incoming Object type into a Derived class type using a void*
pointer. 我的总体意图是使用
void*
指针将任何传入的Object类型转换为Derived类类型。 I hope you understand what I mean. 我希望你明白我的意思。
For example: 例如:
void dynamicCast(void * vptr)
{
BASE * pbase = new DERIVED;
DERIVED * pder;
pder = dynamic_cast<DERIVED *>(vbase);
}
I should be able to pass any type of pointer to the dynamicCast
function and it should be converted to the derived class pointer. 我应该能够将任何类型的指针传递给
dynamicCast
函数,并且应该将其转换为派生类指针。
When you convert a pointer to an object type into a pointer to void, the only valid conversion for that void pointer is back to its original type . 当您将对象类型的指针转换为void的指针时,该void指针的唯一有效转换是返回其原始类型 。 You can't use
dynamic_cast
on a pointer to void
because void
is not a polymorphic type, so you do it with a static_cast
. 您不能在指向
void
的指针上使用dynamic_cast
,因为void
不是多态类型,因此可以使用static_cast
。 Like this: 像这样:
BASE *pbase = new DERIVED;
void *vbase = pbase; // Ok; implicit conversion to void*
BASE *pbase1 = static_cast<BASE*>(vbase); // the cast is required
Once you've gotten back the pointer to BASE
, of course, you can use dynamic_cast
to convert it to a pointer to the derived type: 当然,一旦获得指向
BASE
的指针,就可以使用dynamic_cast
将其转换为指向派生类型的指针:
DERIVED *pder = dynamic_cast<DERIVED*>(pbase1);
You cannot use dynamic_cast
on a void *
. 您不能在
void *
上使用dynamic_cast
。
From the specification, for dynamic_cast<T>(v)
: 根据规范,对于
dynamic_cast<T>(v)
:
If T is a pointer type, v shall be a prvalue of a pointer to complete class type , and the result is a prvalue of type T. ...
如果T是一个指针类型,则v应该是一个指向完整类type的指针的prvalue,结果是类型T的prvalue。...
What you should do is to let all your classes derive from the same polymorphic base class (which has at least one virtual function) BASE
, and use BASE *
instead of void *
. 您应该做的是让所有类都从同一个多态基类(具有至少一个虚函数)
BASE
派生,并使用BASE *
代替void *
。
Your generic linked list should be like this: 您的通用链接列表应如下所示:
class Node
{
Node* next;
void* vdata;
}
That's the only data structure strictly required, but you might want a circular list, or a base node to keep track of the end of the list, or a doubly-linked list. 那是严格要求的唯一数据结构,但是您可能想要一个循环列表,或者一个基本节点来跟踪列表的末尾,或者是一个双向链接的列表。
Caller passes you a void*, you create a new node, set "vdata" and add the node to your list. 呼叫者向您传递了一个void *,您创建了一个新节点,设置了“ vdata”并将该节点添加到列表中。
I think there is a design or/and comprehension problem 我认为存在设计或理解问题
As explained you can not dynamic_cast
from a void*
. 如前所述,您不能从
void*
dynamic_cast
。
Why? 为什么? Because
dynamic_cast
needs some Run-Time Type Information (RTTI) to do the cast (see this link for further details). 因为
dynamic_cast
需要一些运行时类型信息(RTTI)进行转换(请参阅此链接以获取更多详细信息)。 From void*
alone, the C++ code has no chance to know where this information is. 仅凭
void*
,C ++代码就没有机会知道此信息的位置。 The minimum is to use a pointer to an object having such RTTI information. 最低要求是使用指向具有此类RTTI信息的对象的指针。
This information is created and bounded to any class having at least one virtual method . 创建此信息并将其绑定到具有至少一个虚拟方法的任何类。 If there is no virtual method this information is not included.
如果没有虚拟方法,则不包含此信息。 That is the reason why this does not work:
这就是为什么这不起作用的原因:
struct A
{
};
struct B : A
{
};
int main()
{
B b;
A *a = &b;
dynamic_cast<B *>(a); // YOUR COMPILE TIME ERROR
}
A fix is to add a virtual method to A. Here I have added a virtual destructor as this is generally a good thing 解决方法是向A添加虚拟方法。在这里,我添加了虚拟析构函数,因为这通常是一件好事
struct A
{
virtual ~A() = default;
};
struct B : A
{
};
int main()
{
B b;
A *a = &b;
dynamic_cast<B *>(a); // OK
}
Also note that dynamic_cast
allows you to check that the conversion was legal. 还要注意,
dynamic_cast
允许您检查转换是否合法。
For instance we can add a C class and check: 例如,我们可以添加一个C类并检查:
struct C
{
};
int main()
{
B b;
A *a = &b;
assert(dynamic_cast<B *>(a)!=nullptr); // OK
assert(dynamic_cast<C *>(a)==nullptr); // OK can not cast A to C
}
This kind of run-time operations are not free. 这种运行时操作不是免费的。 If you search for maximum speed to can use this trick:
如果您搜索最大速度可以使用此技巧:
assert(dynamic_cast<B *>(a)!=nullptr);
B* b=static_cast<B*>(a);
In debug mode you will check if everything is ok and in release mode with the -DNDEBUG
flag to remove the assert
you will only use the static_cast
在调试模式下,您将检查一切是否正常,在释放模式下,使用
-DNDEBUG
标志删除assert
您将仅使用static_cast
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.