一般如何从 void * 指针动态转换?

Vig*_*ran 6 c++ dynamic-cast void-pointers

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;
}
Run Code Online (Sandbox Code Playgroud)

每当我尝试将void*指针动态转换为派生类指针时,都会收到以下错误:

无法将“vbase”(类型为“void*”)动态转换为“class DERIVED*”类型(源不是指向类的指针)

我搜索了 StackOverflow 并遵循建议在基类中实现虚拟函数以避免错误。我究竟做错了什么?这有可能吗?

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

例如:

void dynamicCast(void * vptr)
{
    BASE * pbase = new DERIVED;
    DERIVED * pder;

    pder = dynamic_cast<DERIVED *>(vbase);
}
Run Code Online (Sandbox Code Playgroud)

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

Pic*_*ent 4

我认为存在设计或/和理解问题

正如所解释的,你不能dynamic_cast从 a void*

为什么?因为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
}
Run Code Online (Sandbox Code Playgroud)

解决方法是向 A 添加一个虚拟方法。这里我添加了一个虚拟析构函数,因为这通常是一件好事

struct A
{
   virtual ~A() = default;
};

struct B : A
{
};

int main()
{
  B  b;
  A *a = &b;

  dynamic_cast<B *>(a);  // OK
}
Run Code Online (Sandbox Code Playgroud)

另请注意,它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 
}
Run Code Online (Sandbox Code Playgroud)

这种运行时操作不是免费的。如果您搜索最大速度可以使用此技巧:

assert(dynamic_cast<B *>(a)!=nullptr);
B* b=static_cast<B*>(a);
Run Code Online (Sandbox Code Playgroud)

在调试模式下,您将检查一切是否正常,在发布模式下,使用标记-DNDEBUG删除assert您将仅使用static_cast