[英]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;
}
每当我尝试将void*
指针动态转换为派生类指针时,都会出现以下错误:
无法dynamic_cast'vbase'(类型'void *')键入'class DERIVED *'(源不是指向class的指针)
我搜索了StackOverflow,并按照建议在基类中实现了一个虚函数,以避免出现错误。 我究竟做错了什么? 这有可能吗?
我的总体意图是使用void*
指针将任何传入的Object类型转换为Derived类类型。 我希望你明白我的意思。
例如:
void dynamicCast(void * vptr)
{
BASE * pbase = new DERIVED;
DERIVED * pder;
pder = dynamic_cast<DERIVED *>(vbase);
}
我应该能够将任何类型的指针传递给dynamicCast
函数,并且应该将其转换为派生类指针。
当您将对象类型的指针转换为void的指针时,该void指针的唯一有效转换是返回其原始类型 。 您不能在指向void
的指针上使用dynamic_cast
,因为void
不是多态类型,因此可以使用static_cast
。 像这样:
BASE *pbase = new DERIVED;
void *vbase = pbase; // Ok; implicit conversion to void*
BASE *pbase1 = static_cast<BASE*>(vbase); // the cast is required
当然,一旦获得指向BASE
的指针,就可以使用dynamic_cast
将其转换为指向派生类型的指针:
DERIVED *pder = dynamic_cast<DERIVED*>(pbase1);
您不能在void *
上使用dynamic_cast
。
根据规范,对于dynamic_cast<T>(v)
:
如果T是一个指针类型,则v应该是一个指向完整类type的指针的prvalue,结果是类型T的prvalue。...
您应该做的是让所有类都从同一个多态基类(具有至少一个虚函数) BASE
派生,并使用BASE *
代替void *
。
您的通用链接列表应如下所示:
class Node
{
Node* next;
void* vdata;
}
那是严格要求的唯一数据结构,但是您可能想要一个循环列表,或者一个基本节点来跟踪列表的末尾,或者是一个双向链接的列表。
呼叫者向您传递了一个void *,您创建了一个新节点,设置了“ vdata”并将该节点添加到列表中。
我认为存在设计或理解问题
如前所述,您不能从void*
dynamic_cast
。
为什么? 因为dynamic_cast
需要一些运行时类型信息(RTTI)进行转换(请参阅此链接以获取更多详细信息)。 仅凭void*
,C ++代码就没有机会知道此信息的位置。 最低要求是使用指向具有此类RTTI信息的对象的指针。
创建此信息并将其绑定到具有至少一个虚拟方法的任何类。 如果没有虚拟方法,则不包含此信息。 这就是为什么这不起作用的原因:
struct A
{
};
struct B : A
{
};
int main()
{
B b;
A *a = &b;
dynamic_cast<B *>(a); // YOUR COMPILE TIME ERROR
}
解决方法是向A添加虚拟方法。在这里,我添加了虚拟析构函数,因为这通常是一件好事
struct A
{
virtual ~A() = default;
};
struct B : A
{
};
int main()
{
B b;
A *a = &b;
dynamic_cast<B *>(a); // OK
}
还要注意, dynamic_cast
允许您检查转换是否合法。
例如,我们可以添加一个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
}
这种运行时操作不是免费的。 如果您搜索最大速度可以使用此技巧:
assert(dynamic_cast<B *>(a)!=nullptr);
B* b=static_cast<B*>(a);
在调试模式下,您将检查一切是否正常,在释放模式下,使用-DNDEBUG
标志删除assert
您将仅使用static_cast
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.