我如何从void *指针中动态施放

How do I dynamically cast from a void * pointer generically?

本文关键字:指针 动态 施放 void      更新时间:2023-10-16
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*')键入'类派生*'(源不是类的指针)

我已经搜索了Stackoverflow,并遵循建议,通过在基类中实现虚拟功能以避免错误。我究竟做错了什么?这完全可以吗?

我的总体意图是使用void*指针将任何传入的对象类型投入到派生类类型中。我希望你明白我的意思。

例如:

void dynamicCast(void * vptr)
{
    BASE * pbase = new DERIVED;
    DERIVED * pder;
    pder = dynamic_cast<DERIVED *>(vbase);
}

我应该能够将任何类型的指针传递给dynamicCast函数,并应将其转换为派生的类指针。

我认为有一个设计或/和理解问题

正如解释的那样,您无法从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中添加虚拟方法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

当您将指针转换为对象类型转换为指向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是的prvalue>"完整类型" 的指针,结果是T型T型。...

您应该做的是让所有类都从同一多态基类(至少具有一个虚拟函数)BASE衍生而来,并使用BASE *而不是void *

您的通用链接列表应该像这样:

class Node
{
    Node* next;
    void* vdata;
}

这是严格要求的唯一数据结构,但是您可能需要一个圆形列表或一个基本节点来跟踪列表的结尾或双关联列表。

呼叫者通过一个void*,您创建一个新节点,设置" vdata"并将节点添加到列表中。