繁体   English   中英

我如何动态地从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*指针动态转换为派生类指针时,都会出现以下错误:

无法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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM