C++ 类型转换 :C语言的类型转换、C++的四种强制类型转换、explicit
文章目錄
- C語言中的類型轉換
- 隱式類型轉換
- 顯式類型轉換
- C++ 強制類型轉換
- static_cast
- reinterpret_cast
- const_cast
- dynamic_cast
- explicit
C語言中的類型轉換
C語言中的類型轉換,通常發生在傳參時參數類型不匹配,又或是接收的返回值類型不一致、賦值雙方類型不同的情景,就會需要用到類型轉換。主要分為隱式類型轉換與顯示類型轉換兩種。
隱式類型轉換
編譯器在編譯階段自動進行,通常適用于相近的類型,如果不能轉換則會編譯失敗。
例如:
顯式類型轉換
需要用戶自己處理,通常用于不相近類型的轉換。
如:
從上面可以看出來,C語言的類型轉換使用起來很簡單,但是也有很大的缺點。
C++ 強制類型轉換
標準C++為了加強類型轉換的可視性,引入了四種命名的強制類型轉換操作符:static_cast、reinterpret_cast、const_cast、dynamic_cast
static_cast
static_cast用于非多態類型的轉換(靜態轉換),編譯器隱式執行的任何類型轉換都可用static_cast,但它不能用于兩個不相關的類型進行轉換。(即對應C語言中的隱式類型轉換)
int main() {double d = 1.9;int i = static_cast<int>(d);cout << i; }reinterpret_cast
reinterpret_cast是一種較為危險的類型轉換,通常為操作數的位模式提供較低層次的重新解釋,用于將一種類型轉換為另一種不同的類型,通常適用于指針、引用、以及整數之間的類型轉換。
int main() {int i = 9;int* p = &i;double* p2 = reinterpret_cast<double*>(p);cout << *p2 << ' ' << *p; }
如上面所說,這種轉換十分容易導致錯誤的發生,因為指針類型其實是其指向的地址的類型,決定了指針看待這段地址的方式,它該如何讀取數據。這里我把int改成了double,使得他原本應該讀取4個字節,而變成了8個字節,就導致了數據的變化。如果使用不當很容易會造成越界訪問導致程序崩潰。
const_cast
const_cast通常用于刪除變量的const屬性
如果想要修改const變量的值,就需要用volatile來取消編譯器優化。因為const變量創建后會被放入寄存器中,只有我們取const變量的地址時,他才會在內存中申請空間,而我們修改的是const變量在內存中的值,但是由于編譯器優化,當使用const變量時就會到寄存器中去取值,所以需要用volatile取消編譯器優化,讓其每次在內存中取值。
不加volatile時
int main() {const int ci = 10;int* pi = const_cast<int*>(&ci); // 對應c語言強制類型轉換中去掉const屬性的(不相近類型)*pi = 20;cout << ci << ' ' << *pi; }
加volatile時
dynamic_cast
dynamic_cast是一種動態的類型轉換,是C++新增的概念,用于將一個父類對象的指針/引用轉換為子類對象的指針或引用。
派生類可以賦值給基類的對象、指針或者引用,這樣的賦值也叫做對象切割。
例如Human類和Student類
從這幅圖可以看出來,當把派生類賦值給基類時,可以通過切割掉多出來的成員如_stuNum的方式來完成賦值。
但是基類對象如果想賦值給派生類,則不可以,因為他不能憑空多一個_stuNum成員出來。
但是基類的指針或者引用卻可以強制類型轉換賦值給派生類對象, 如:
這個過程有可能成功,也有可能會因為越界導致出現問題。 如果使用C語言的強制類型轉換,很可能就會出現問題,因為其沒有安全保障。而如果使用dynamic_cast,則能夠保證安全,因為其會先檢查轉換是否能夠成功,如果不能成功則返回0,能則直接轉換。
但是dynamic_cast的向下轉換只支持繼承中的多態類型,也就是父類之中必須包含虛函數。
int main() {Human h1;Student s1;Human* hPtr1 = &s1;//指向派生類對象Human* hPtr2 = &h1;//指向基類對象//傳統方法Student* pPtr = (Student*)hPtr1;//沒問題Student* pPtr = (Student*)hPtr2;//有時候沒有問題,但是會存在越界風險//dynamic_castStudent* pPtr = dynamic_cast<Student*>(hPtr2);return 0; }注意:
dynamic_cast是如何識別父類的指針指向的是父類對象還是子類對象的呢?其原理就是在運行時通過查找虛函數表上面的標識信息,來確認其指向的到底是父類還是子類,這也就是為什么只能用于含有虛函數的類。
這種在運行中進行類型識別的方法,也叫做RTTI,C++中有很多支持RTTI的方法,如dynamic_cast,typeid,decltype
explicit
explicit關鍵字主要用來阻止轉換構造函數而進行隱式類型轉換的發生
class Date { public:Date(int year = 0, int month = 4, int day = 24):_year(year),_month(month),_day(day){}int _year;int _month;int _day; };int main() {Date d1(2020, 4, 24);Date d2 = 2020;//C++98Date d3 = { 2020, 4 }; //C++11Date d4 = { 2020, 4, 24 }; //C+11 }對于這里的d2,我們用2020給它賦值,而d3和d4分別用了列表來給它賦值,并且這四個對象它們最后的值是一模一樣的,那是為什么呢?這里的2020明明是一個整型,d3和d4是一個列表,為什么能夠給對象賦值呢?
這里就牽扯到了隱式的類型轉換
這里其實是先用這個整型值來調用了全缺省的構造函數來創建了一個臨時對象,再使用這個對象來為d2,d3,d4賦值。
這是一種很容易引起誤會的寫法,所以c++提供了關鍵字explicit,用這個關鍵字修飾的函數就會禁止隱式類型的轉化
這時這種隱式類型轉換就不會發生了
總結
以上是生活随笔為你收集整理的C++ 类型转换 :C语言的类型转换、C++的四种强制类型转换、explicit的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++ 智能指针 :内存泄漏、 RAII
- 下一篇: C++ STL : SGI-STL空间配