簡體   English   中英

“upcast”方法指針並將其與基類指針一起使用是否安全?

[英]Is it safe to “upcast” a method pointer and use it with base class pointer?

假設我有一個可以保存基類方法地址的指針類型。 我可以為其分配子類方法的地址並期望它正常工作嗎? 在我的情況下,我使用它與基類指針,對象的動態類型是派生類。

struct B
{
    typedef void (B::*MethodPtr)();
};

struct D: public B
{
    void foo() { cout<<"foo"<<endl; }
};

int main(int argc, char* argv[])
{
    D d;
    B* pb = &d;

    //is the following ok, or undefined behavior?
    B::MethodPtr mp = static_cast<B::MethodPtr>(&D::foo);
    (pb->*mp)();
}

在討論static_cast時,標准說明了這一點:

5.2.9.9類型“指向類型為cv1 T的D成員的指針”的右值可以轉換為類型為“指向cv2 T類型B的成員的指針”的右值,其中B是D的基類(第10節) ,如果存在從“指向T類型的B的成員的指針”到“指向T類型的D的成員的指針”的有效標准轉換(4.11),並且cv2與cv-qualification相同,或者更高的cv-qualification, CV1。 63)空成員指針值(4.11)被轉換為目標類型的空成員指針值。 如果類B包含原始成員,或者是包含原始成員的類的基類或派生類,則指向成員的結果指針指向原始成員。 否則,演員的結果是不確定的。 [注意:雖然B類不需要包含原始成員,但是取消引用成員指針的對象的動態類型必須包含原始成員; 見5.5。]

和往常一樣,我很難破譯標准。 它有點說沒關系,但我不能100%確定上述文本是否真的適用於我的示例代碼中的情況。

這是有效的。

如果B類包含原始成員,

B不包含D :: Foo,所以沒有。

或者是包含原始成員的類的基礎[...]

B是D的基礎,所以這就成立了。 結果是:

生成的指向成員的指針指向原始成員

第5.2.9條第9款規定,如果您也可以按照第4.11節的規定進行向下轉換,則只能進行轉發:

類型為“cv T類型的B成員的指針”的r值,其中B是類類型,可以轉換為類型為“指向類型為cv T的D的成員的指針”的右值,其中D是派生類(如果B是不可訪問的(第11條),D的模糊(10.2)或虛擬(10.1)基類,則需要這種轉換的程序是不正確的。

這只是說只要B可以訪問就可以向下轉換,不是虛擬的,只在D的繼承圖中出現一次。

upcasting方法指針固有的危險是你可以在實際類型為B的對象上調用mp 。只要處理D :: *的代碼塊也處理D *,你就可以避免這種情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM