日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ 类型转换 :C语言的类型转换、C++的四种强制类型转换、explicit

發布時間:2024/4/11 c/c++ 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ 类型转换 :C语言的类型转换、C++的四种强制类型转换、explicit 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • C語言中的類型轉換
    • 隱式類型轉換
    • 顯式類型轉換
  • C++ 強制類型轉換
    • static_cast
    • reinterpret_cast
    • const_cast
    • dynamic_cast
    • explicit


C語言中的類型轉換

C語言中的類型轉換,通常發生在傳參時參數類型不匹配,又或是接收的返回值類型不一致賦值雙方類型不同的情景,就會需要用到類型轉換。主要分為隱式類型轉換顯示類型轉換兩種。

隱式類型轉換

編譯器在編譯階段自動進行通常適用于相近的類型,如果不能轉換則會編譯失敗。
例如:

void print(int i) {cout << i << endl; } int main() {double d = 1.9;print(d);return 0; }

顯式類型轉換

需要用戶自己處理,通常用于不相近類型的轉換
如:

int main() {int i = 9;int* p = &i;//將指針轉換為地址int addr = (int)p;cout << addr; }

從上面可以看出來,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時

    int main() {volatile const int ci = 10;int* pi = const_cast<int*>(&ci); // 對應c語言強制類型轉換中去掉const屬性的(不相近類型)*pi = 20;cout << ci << ' ' << *pi; }


    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只能用于含有虛函數的類
  • dynamic_cast會先檢查是否能轉換成功,能成功則轉換,不能則返回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的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。