簡體   English   中英

什么時候是`static_cast <Base*> (的static_cast <void*> (派生))`從指向派生類的指針有效嗎?

[英]When is a `static_cast<Base*>(static_cast<void*>(derived))` from a pointer to a derived class valid?

對於這個問題,不應涉及多態,即沒有虛方法,也沒有虛基類。 萬一重要,我的案子不涉及任何這些。

假設我有一個Derived類,它有一個類型為Base的明確可訪問父類,沒有多態(沒有虛方法,沒有虛基類),但可能涉及間接和/或多重繼承。 進一步假設我有個有效的指針Derived *derived (指向類型的對象Derived或其亞類)。

在這種情況下,我相信static_cast<Base*>(derived)是有效的(產生有效的可用指針)。 BaseDerived之間的祖先鏈涉及多重繼承時,此static_cast可能意味着指針調整以在Derived實例中定位Base實例。 為此,編譯器需要知道繼承鏈,在這種情況下他會這樣做。 但是,如果插入了void *的中間轉換,則會從編譯器中隱藏該繼承鏈信息。 對於哪個繼承鏈是這樣的靜態轉換有效嗎? 我期待以下之一:

  • 一個都沒有? 除非指針確實指向確切類型,否則從void指針訪問static_cast是未定義的行為。
  • 對於沒有多重繼承的所有鏈? 然后,編譯器可以保證Base總是在Derived的開頭 - 但標准是什么?
  • 對於在所有中間多重繼承鏈的第一個父類中找到Base的所有鏈? 也許BaseDerived的開頭仍然匹配?
  • 總是? static_cast到void指針總是可以調整到第一個父節點的開頭,而static_cast從void指針撤消那個調整。 但是,通過多重繼承,“第一個父母”不一定是所有父母的父母。

static_cast<Base*>(static_cast<void*>(derived))在C ++標准中有一個名稱。 它被稱為reinterpret_cast 它在[expr.reinterpret.cast]第7段中指定:

可以將對象指針顯式轉換為不同類型的對象指針。 當對象指針類型的prvalue v被轉換為對象指針類型“指向cv T的指針”時,結果是static_cast<cv T*>(static_cast<cv void*>(v)) [注意:將“指向T1的指針”類型的prvalue轉換為“指向T2的指針”類型(其中T1和T2是對象類型,T2的對齊要求不比T1更嚴格)並返回其原始類型產生原始指針值。 - 結束說明]

reinterpret_cast是告訴編譯器將指針視為其他東西。 編譯器可以或將根據此指令進行調整。 如果我們說謊,那么行為就是未定義的。 標准是否說這樣的reinterpret_cast有效? 它實際上。 [basic.compound]第4段中定義了指針互換性的概念:

如果出現以下情況,則兩個對象a和b是指針可互換的:

  • 它們是同一個對象,或者
  • 一個是union對象,另一個是該對象的非靜態數據成員([class.union]),或
  • 一個是標准布局類對象,另一個是該對象的第一個非靜態數據成員,或者,如果該對象沒有非靜態數據成員,則該對象的任何基類子對象([class.mem]) , 要么
  • 存在對象c,使得a和c是指針可互換的,並且c和b是指針可互換的。

如果兩個對象是指針可互換的,則它們具有相同的地址,並且可以通過reinterpret_cast從指向另一個的指針獲得指向一個對象的指針。 [注意:數組對象及其第一個元素不是指針可互換的,即使它們具有相同的地址。 - 結束說明]

第三個子彈是你的答案。 類層次結構中的對象必須支持限制(從頂部基礎到大多數派生的標准布局 ),然后才能保證轉換為定義良好的結果。

暫無
暫無

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

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