简体   繁体   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;
}

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.

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