1
#include <cassert> 

struct A { int a; }; 
struct I1 : A { int a; }; 
struct I2 : A { int a; }; 
struct D : I1, I2 { int a; }; 

using namespace std; 

int main() 
{ 
    auto d = new D; 

    auto a = static_cast<I2*>(d); 
    assert((void*)(a) != (void*)(d)); // OK 

    auto b = reinterpret_cast<I2*>(d); 
    assert((void*)(b) == (void*)(d)); // OK under VC++. Is it guaranteed? 
} 

reinterpret_cast確保它不會改變其操作數的值嗎?reinterpret_cast保證它不會改變其操作數的值嗎?

+0

注意:'new'在這裏沒用;你可以在堆棧分配的對象上完美地使用多態。 –

回答

3

reinterpret_cast保證它不會改變其操作數的值嗎?

TL; DR我覺得,在某些條件下。

擔保應該保持只要目標類型的對齊要求不比源類型更嚴格。否則,轉換的影響是未指定的。


最簡單的方法是要求標準,並且具體地:§5.2.10[expr.reinterpret.cast]

7 /對象指針可以顯式轉換爲對象當一個類型爲「指向T1的指針」的指針v被轉換爲類型「指向cv T2」的類型指針時,如果T1和T2都是標準佈局類型(3.9),則結果爲static_cast<cv T2*>(static_cast<cv void*>(v)) T2的對齊要求不比T1的要求更嚴格,或者其中任一類型爲void。將「指向T1的指針」類型的prvalue轉換爲類型「指向T2的指針」(其中T1和T2是對象類型,並且T2的對齊要求不比T1的對齊要求更嚴格)並返回到其原始類型,指針值。任何其他此類指針轉換的結果都未指定。

在你的情況因爲在這個層次沒有virtual方法,該類型是標準佈局類型。而且,由於確實都具有相同的對齊要求(因爲它們包含相同的值),那麼我們確實在這裏,因此匹配以及指定的效果:

reinterpret_cast<I2*>(d) 

等同於:

static_cast<I2*>(static_cast<void*>(d)) 

因此我們需要回到§5.2.9[expr.static。投]

7 /不含有一個左值到右值(4.1)的任何標準轉換序列(第4章)的倒數,陣列到指針(4.2),函數到指針( 4.3),空指針(4.10),空成員指針(4.11)或布爾(4.12)轉換可以使用static_cast明確執行。如果程序使用static_cast執行不合格標準轉換序列的反轉,則該程序不合格。

T*void*是根據標準轉換序列§4.10[conv.ptr],第2段;所以我假設這意味着static_castvoid*T*應產生相同的地址(假設它首先匹配T的對齊要求)。

13 /類型的prvalue「指針CV1空隙」可以被轉換成類型的prvalue「指針CV2 T,」,其中T是一個對象類型和CV2是相同的cv資格,或者比cv資格更高,cv1。空指針值被轉換爲目標類型的空指針值。指向對象的類型指針的值被轉換爲「指向cvvoid」,並且可能具有不同的cv限定,應該具有其原始值。 [實施例

T* p1 = new T; 
const T* p2 = static_cast<const T*>(static_cast<void*>(p1)); 
bool b = p1 == p2; // b will have the value true. 

末端示例]

不幸的是,該示例是關閉(相對於你的情況下);所以我們沒有從這方面得到很多。我只是爲了完整性而引用它,因爲它是相關的。

1

編號 嗯,我必須在這裏輸入一些不錯的字符來滿足SO傻瓜,但答案依然如此。但是,我可能會使用這些額外的文本提到,當然,您擁有的有效保證可能比C++標準提供的更實用。但是,對於任何擁有大腦的人來說(對於程序員來說都是這樣),這是很明顯的,所以這可能聽起來有點光顧這一點,但第三方面,這應該是足夠的文本。


呵呵,現在看你的代碼,我覺得第一個斷言不應該成立(一般),因爲我記得沒有保證約基類子對象的存儲順序。你可能想檢查一下。在實踐中也通過與其他基類做相同的處理。

相關問題