簡體   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