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,并且它应该转换为派生类指针。
我认为存在设计或/和理解问题
正如所解释的,你不能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