一般如何从 void * 指针动态转换?
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*
指针动态转换为派生的 class 指针时,我都会收到以下错误:
cannot dynamic_cast 'vbase' (of type 'void*') to type 'class DERIVED*' (source is not a pointer to class)
我搜索了 Whosebug 并按照建议在基 class 中实现了一个虚函数来避免错误。我究竟做错了什么?
这可能吗?
我的总体意图是使用 void*
指针将任何传入的对象类型转换为派生的 class 类型。希望你明白我的意思。
例如:
void dynamicCast(void * vptr)
{
BASE * pbase = new DERIVED;
DERIVED * pder;
pder = dynamic_cast<DERIVED *>(vbase);
}
我应该能够将任何类型的指针传递给 dynamicCast
函数,并且它应该被转换为派生的 class 指针。
您不能在 void *
上使用 dynamic_cast
。
根据规范,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. ...
你应该做的是让你所有的 classes 派生自同一个多态基 class(至少有一个虚函数)BASE
,并使用 BASE *
而不是 void *
.
你的通用链表应该是这样的:
class Node
{
Node* next;
void* vdata;
}
这是唯一严格要求的数据结构,但您可能需要一个循环列表,或一个跟踪列表末尾的基节点,或一个双向链表。
调用方传递给您一个 void*,您创建一个新节点,设置 "vdata" 并将该节点添加到您的列表中。
当您将指向对象类型的指针转换为指向 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);
我认为有一个设计or/and理解问题
如前所述,您不能 dynamic_cast
来自 void*
。
为什么?因为 dynamic_cast
需要一些 运行-时间类型信息 (RTTI) 来进行转换(请参阅 this link 了解更多详细信息)。仅从 void*
开始,C++ 代码就没有机会知道此信息在哪里。最低限度是使用指向具有此类 RTTI 信息的对象的指针。
创建此信息并将其绑定到任何具有至少一个 虚方法 的 class。如果没有虚拟方法,则不包括此信息。这就是这个 不 工作的原因:
struct A
{
};
struct B : A
{
};
int main()
{
B b;
A *a = &b;
dynamic_cast<B *>(a); // YOUR COMPILE TIME ERROR
}
一个解决方法是给 A 添加一个虚方法。这里我添加了一个虚析构函数 this is generally a good thing
struct A
{
virtual ~A() = default;
};
struct B : A
{
};
int main()
{
B b;
A *a = &b;
dynamic_cast<B *>(a); // OK
}
另请注意,dynamic_cast
允许您检查转换是否合法。
例如我们可以添加 C class 并检查:
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
}
这种运行-time的操作不是免费的。如果你搜索最大速度可以使用这个技巧:
assert(dynamic_cast<B *>(a)!=nullptr);
B* b=static_cast<B*>(a);
在调试模式下,您将检查是否一切正常,在发布模式下,使用 -DNDEBUG
标志删除 assert
您将只使用 static_cast
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*
指针动态转换为派生的 class 指针时,我都会收到以下错误:
cannot dynamic_cast 'vbase' (of type 'void*') to type 'class DERIVED*' (source is not a pointer to class)
我搜索了 Whosebug 并按照建议在基 class 中实现了一个虚函数来避免错误。我究竟做错了什么? 这可能吗?
我的总体意图是使用 void*
指针将任何传入的对象类型转换为派生的 class 类型。希望你明白我的意思。
例如:
void dynamicCast(void * vptr)
{
BASE * pbase = new DERIVED;
DERIVED * pder;
pder = dynamic_cast<DERIVED *>(vbase);
}
我应该能够将任何类型的指针传递给 dynamicCast
函数,并且它应该被转换为派生的 class 指针。
您不能在 void *
上使用 dynamic_cast
。
根据规范,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. ...
你应该做的是让你所有的 classes 派生自同一个多态基 class(至少有一个虚函数)BASE
,并使用 BASE *
而不是 void *
.
你的通用链表应该是这样的:
class Node
{
Node* next;
void* vdata;
}
这是唯一严格要求的数据结构,但您可能需要一个循环列表,或一个跟踪列表末尾的基节点,或一个双向链表。
调用方传递给您一个 void*,您创建一个新节点,设置 "vdata" 并将该节点添加到您的列表中。
当您将指向对象类型的指针转换为指向 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);
我认为有一个设计or/and理解问题
如前所述,您不能 dynamic_cast
来自 void*
。
为什么?因为 dynamic_cast
需要一些 运行-时间类型信息 (RTTI) 来进行转换(请参阅 this link 了解更多详细信息)。仅从 void*
开始,C++ 代码就没有机会知道此信息在哪里。最低限度是使用指向具有此类 RTTI 信息的对象的指针。
创建此信息并将其绑定到任何具有至少一个 虚方法 的 class。如果没有虚拟方法,则不包括此信息。这就是这个 不 工作的原因:
struct A
{
};
struct B : A
{
};
int main()
{
B b;
A *a = &b;
dynamic_cast<B *>(a); // YOUR COMPILE TIME ERROR
}
一个解决方法是给 A 添加一个虚方法。这里我添加了一个虚析构函数 this is generally a good thing
struct A
{
virtual ~A() = default;
};
struct B : A
{
};
int main()
{
B b;
A *a = &b;
dynamic_cast<B *>(a); // OK
}
另请注意,dynamic_cast
允许您检查转换是否合法。
例如我们可以添加 C class 并检查:
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
}
这种运行-time的操作不是免费的。如果你搜索最大速度可以使用这个技巧:
assert(dynamic_cast<B *>(a)!=nullptr);
B* b=static_cast<B*>(a);
在调试模式下,您将检查是否一切正常,在发布模式下,使用 -DNDEBUG
标志删除 assert
您将只使用 static_cast