原文地址https://www.cnblogs.com/xiangtingshen/p/11063805.html
reinterpret意為“重新解釋”
reinterpret_cast是C++中與C風格類型轉換最接近的類型轉換運算符。它讓程序員能夠將一種對象類型轉換為另一種,不管它們是否相關。
reinterpret_cast用在任意指針(或引用)類型之間的轉換;以及指針與足夠大的整數類型之間的轉換;從整數類型(包括枚舉類型)到指針類型,無視大小。
(所謂"足夠大的整數類型",取決於操作系統的參數,如果是32位的操作系統,就需要整形(int)以上的;如果是64位的操作系統,則至少需要長整形(long)。具體大小可以通過sizeof運算符來查看)。
【注意】reinterpret_cast不能用於內置類型之間的轉換,只能用於不同指針之間的轉換。
CBase* pBase = new CBase( ) ; CDerived* pDerived = reinterpret_cast<CDerived*>(pBase) ;
這種類型轉換實際上是強制編譯器接受static_cast通常不允許的類型轉換,它並沒有改變指針值的二進制表示,只是改變了編譯器對源對象的解釋方式。
【應盡量避免使用reinterpret_cast】
reinterpret_cast VS static_cast
static_cast主要管:有繼承關系類的指針和內置數據類型的轉換(和C的內置類型轉換規則一致,可能改變底層的位,也可能不改變)。
reinterpret_cast主要管:所有指針(引用)之間的轉換
在它們管理的交叉點處——有繼承關系的指針的轉換,處理方式有所不同。
static_cast和reinterpret_cast的區別主要在於多重繼承
class A
{
public:
int m_a;
};
class B
{
public:
int m_b;
};
class C : public A, public B {};
C c;
printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));
前兩個的輸出值是相同的,最后一個則會在原基礎上偏移4個字節。
這是因為static_cast計算了父子類指針轉換的偏移量,並將之轉換到正確的地址(c里面有m_a,m_b,轉換為B*指針后指到m_b處),而reinterpret_cast卻不會做這一層轉換。
reinterpret_cast VS const_cast
reinterpret_cast不能像const_cast那樣去除const修飾符。
int main()
{
typedef void (*FunctionPointer)(int);
int value = 21;
const int* pointer = &value;
int * pointer_r = reinterpret_cast<int*> (pointer); //編譯報錯
FunctionPointer funcP = reinterpret_cast<FunctionPointer> (pointer);
}
reinterpret_cast只能改變指針(或引用)的解釋方式,不能把其上的const鎖轉換掉。
const_cast
const_cast讓程序員能夠關閉對象的訪問修飾符const。
在理想的情況下,程序員將經常在正確的地方使用關鍵字const。
但是現實世界,經常可以看到該使用const的地方沒有使用。
這樣,在外部函數中調用類中的這些成員函數,可能會報錯。
CSomeClass
{
public:
….
void DisplayMember( ) ;
};
void DisplayAllData( const CSomeClass& mData )
{
mData.DisplayMembers ( ) ; //編譯報錯
}
為什么會編譯報錯?
因為DisplayMembers為普通的成員函數,故DisplayMembers成員函數中隱藏的this指針,會被編譯器設置為CSomeClass* this。而mData是被const修飾的,mData.DisplayMembers ( ) ;即是DisplayMembers ( &mData); 這樣,實參和形參類型不一致,編譯器會報錯。
如何修改這一問題?
①把函數列表上mData前的const去掉。
這樣,使代碼的安全性降低,其后的代碼可能會修改mData中的值。
②在成員函數DisplayMembers前添上const。
這樣固然最好,但是如果CSomeClass是第三方的類,我們沒有其源代碼,那怎么辦?
③使用const_cast把mData上的const鎖暫時去掉。
void DisplayAllData( const CSomeClass& mData )
{
CSomeClass& refData = const_cast< CSomeClass &>(mData) ;
refData.DisplayMembers ( ) ;
}
另外:const_cast也可用於指針。
void DisplayAllData( const CSomeClass* pData )
{
CSomeClass* pCastedData = const_cast< CSomeClass *>( pData) ;
pCastedData ->DisplayMembers ( ) ;
}
C++類型轉換符存在的問題:
static_cast的用途可用C風格類型轉換進行處理,且更簡單。
例:
double dPi = 3.14 ; int num1 = static_cast<int>(dPi) ; int num2 = (int)dPi ; CDerived* pDerived1 = static_cast<CDerived*>(pBase) ; CDerived* pDerived2 = (CDerived*)pBase ;
故,Bjarne Stroustrup說:“由於static_cast如此拙劣且難以輸入,因此您在使用它之前很可能會三思。這很不錯,因為類型轉換在現代C++中是最容易避免的。”
因此,在現代C++中,除dynamic_cast外的類型轉換都是可以避免的。
僅當需要滿足遺留應用程序需求時,才需要使用其它類型轉換運算符。在這種情況下,程序員通常傾向於使用C風格類型轉換而不是使用C++類型轉換運算符。
重要的是,應盡量避免使用類型轉換,而一旦使用類型轉換,務必要知道幕后發生的情況。
關於隱式轉換:
例:
#include <iostream>
using namespace std ;
class A
{
int m_nA ;
};
class B
{
int m_nB;
};
class C : public A, public B
{
int m_nC;
};
int main(void)
{
C* pC = new C ;
B* pB = dynamic_cast<B*>(pC) ;
A* pA = dynamic_cast<A*>(pC) ;
if ( pC==pB )
cout << “equal” << endl ;
else
cout << “not equal” << endl ;
if ( (int)pC == (int)pB )
cout << “equal” <<endl ;
else
cout << “not equal” << endl ;
return 0 ;
}
//程序輸出如下:
//equal
//not equal
if ( pC == pB )這里兩端數據類型不同,比較時需要進行隱式類型轉換。( pC == pB )相當於:pC == (C*)pB ;
pB實際上指向的地址是對象C中的子類B的部分,從地址上跟pC不一樣,所以直接比較地址數值的時候是不相同的。故 (int)pC 與(int)pB 不同。
但是:(C*)pB相當於static_cast<C*>(pB)
它們計算了父子類指針轉換的偏移量,並將之轉換到正確的地址(c里面有m_a,m_b,轉換為B*指針后指到m_b處)
【在C++中,涉及相關指針的強制類型轉換,並不是不改變指針值,有時(涉及多重繼承時)會根據需要改變底層值。reinterpret_cast才是只改變解釋方式,不改變底層值。】
【注意】C++中的隱式類型轉換的方式和static_cast的轉換行為類似。(只是static_cast對於不相關指針的轉換無能為力)

