[英]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.