一文帶你探索C++中類型轉換的奧秘
const_cast(常量轉換)
const_cast(常量轉換)是一種類型轉換運算符,用于修改類型的const或volatile屬性。它通常用于將const變量轉換為非常量類型,或者將volatile變量轉換為非volatile類型。用法如下:
const_cast<new_type>(expression)
new_type是你要轉換成的類型,expression是要被轉換的表達式。
示例
int main() { const int a = 10; // int* pA = &a;//編譯錯誤,不能將一個非常量指針指向一個常量對象。 int* pA = const_cast<int*>(&a); *pA = 20; //輸入10 20 cout << "a:" << a << " *pA:" << *pA << endl; }
上面的代碼定義一個 const int
類型的變量 a
,我們想要將其轉換為 int 類型。直接用一個指針pA
指向這個a
時,由于a
本身是const類型,會導致編譯錯誤。所以我們可以用 const_cast 把它做一個類型轉換,去除 a
的 const 修飾符。然后修改 *pA
的值。
但是大家需要注意,最后的打印輸出是a:10 *pA:20
。
即使你使用 const_cast 去除了指向 a
的指針的常量性, *pA = 20
修改了*pA
的值,實際上并不會影響 a
的輸出,這是 C++ 語言的常量性規(guī)則所決定的。因為它是一個常量。在編譯時,編譯器將 a
的值直接插入到代碼中,而不是通過指針 pA
訪問 a。因此無論如何修改 *pA
,a
的值都保持不變。
const_cast 在某些情況下可以提高代碼的可讀性和減少冗余代碼,但也存在一些缺點,例如增加代碼的復雜度和容易產生歧義。
reinterpret_cast(重新解釋轉換)
reinterpret_cast
是一種非常危險類型轉換。它不會檢查我們所指向的內容,也不會檢查我們這個類型的本身。它只是做了一個重新的解釋,我們要在轉換的過程當中,保證它轉換前和轉換后占用的內存大小應該是一致的。用于在不同類型的指針之間進行轉換,用法如下:
reinterpret_cast<new_type>(expression)
示例
int Test() { std::cout << "Test function called." << std::endl; return 0; } int main() { //創(chuàng)建一個 FuncPtr 的函數指針類型。指向沒有參數和返回值的函數。 typedef void(*FuncPtr) (); FuncPtr funcPtr; // funcPtr = &Test; funcPtr = reinterpret_cast<FuncPtr>(&Test); funcPtr(); return 0; }
上述代碼 Test
函數的返回類型是 int,而 FuncPtr
類型是 void(*)()
,這兩者的返回類型不匹配,因此不能將 Test
函數指針直接賦給 funcPtr
。可以通過reinterpret_cast
顯式類型轉換來解決這個問題,funcPtr = reinterpret_cast<FuncPtr>(&Test)
將 Test
函數的指針轉換為 FuncPtr
類型的函數指針。
reinterpret_cast不進行類型檢查非常靈活,可以在不同指針類型之間進行轉換,包括將指針從對象類型轉換為其他類型,或者在整數類型和指針之間進行轉換。但是reinterpret_cast是非常危險的。因為他把這個檢查的大部分工作交給程序員自身來管理的,可能導致轉換不合理或不安全。
static_cast(靜態(tài)轉換)
static_cast(靜態(tài)轉換)可用于對基本類型進行轉換,例如int *
轉double *
,有繼承關系的類對象和類指針之間轉換。要注意的是,如果用static_cast
做一個繼承關系的轉換,安全問題需要由程序員自身來保障。
比如說動物,它有一個類叫鴨子,那么鴨子它一定是一種動物,所以它有動物的行為。但是動物未必都有鴨子的行為,所以如果我們把鴨子轉換成動物,就是一個叫向上轉換的過程。如果向下轉換,那就是把動物轉換成鴨子。但并不是所有的動物都是鴨子,所以這個地方就存在一些潛在的危險。如果我們使用static_cast
就不會發(fā)現這樣的問題。但如果我們使用dynamic_cast
,就會幫我們檢查出來這種錯誤。
示例
class Base { public: Base() : _i(0) {} virtual void T() { cout << "Base:T" << _i << endl; } private: int _i; }; class Derived : public Base { public: Derived() : _j(1) {} virtual void T() { cout << "Derived:T" << _j << endl; } private: int _j; }; void main() { int intValue = 5; double intValue2 = static_cast<double>(intValue); cout << intValue << " " << intValue2 << endl;//5 5 double dValue = 5.6; int dValue2 = static_cast<int>(dValue); cout << dValue << " " << dValue2 << endl;//5.6 5 丟失精度 Base base; Derived derived; Base* pBase; Derived* pDerived; // 父類--》子類 static_cast未做檢查 可能導致運行時錯誤 pDerived = static_cast<Derived*>(&base); if (pDerived == NULL) { cout << "unsafe static cast from Base to Derived" << pDerived << endl; } }
上面的static_cast將base轉化為Derived*,可能導致運行時錯誤。所以在進行類型轉換時,要注意類型匹配規(guī)則。確保轉換是安全的并且符合預期。例如,在進行向下轉型時,需要確保子類對象可以存儲父類對象。
dynamic_cast (動態(tài)轉換)
dynamic_cast (動態(tài)轉換)用于在類的繼承層次之間進行類型轉換,它既允許向上轉型,也允許向下轉型。向下轉型會進行檢測,如果轉換失敗則返回空指針或拋出std::bad_cast異常。用法如下:
dynamic_cast<new_type>(expression)
new_type 和 expression 必須同時是指針類型或者引用類型。
示例
class Base { public: Base() : _i(0) {} virtual void T() { cout << "Base:T" << _i << endl; } private: int _i; }; class Derived : public Base { public: Derived() : _j(1) {} virtual void T() { cout << "Derived:T" << _j << endl; } private: int _j; }; void main() { Base base; Derived derived; Base* pBase; Derived* pDerived; // 父類--》子類 pDerived輸出NULL pDerived = dynamic_cast<Derived*>(&base); if (pDerived == NULL) { cout << "unsafe dynamic cast from Base to Derived" << endl; } }
上述代碼創(chuàng)建了一個基類 Base
和一個派生類 Derived
,然后通過dynamic_cast
,將基類指針Base
轉換為派生類指針 pDerived
。,dynamic_cast
返回 NULL
表示轉換失敗。
在動態(tài)類型轉換中,只能將一個指向派生類對象的指針轉換為基類指針,而不是反過來。這是因為派生類對象包含了基類的部分,但反之并不成立。
如果想安全地將指向基類對象的指針轉換為指向派生類對象的指針,要確保對象實際上是派生類對象。
總結
const_cast
用于轉換指針或引用,去掉類型的const屬性;
reinterpret_cast
重新解釋類型,既不檢查指向的內容,也不檢查指針類型本身;但要求轉換前后的類型所占用內存大小一致,否則將引發(fā)編譯時錯誤。
static_cast
用于基本類型轉換,有繼承關系類對象和類指針之間轉換,由程序員來確保轉換是安全的,它不會產生動態(tài)轉換的類型安全檢查的開銷;
dynamic_cast
只能用于含有虛函數的類,必須用在多態(tài)體系中,用于類層次間的向上和向下轉化;向下轉化時,如果是非法的對于指針返回NULL;
到此這篇關于一文帶你探索C++中類型轉換的奧秘的文章就介紹到這了,更多相關C++類型轉換內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!