【Cpp】第十五章-類型轉換

類型轉換

C中的類型轉換

  C語言中的類型轉換分爲隱式類型轉換強制類型轉換兩種

#include <stdio.h>
int main()
{
    //隱式類型轉換
    int i = 10;
    double d = i;
    printf("%d, %.2lf\n", i, d);
    //強制類型轉換
    i = (int)d;
    printf("%d, %.2lf\n", i, d);
}

  這種從C中繼承而來的類型轉換方式十分不直觀,可視性較差,不便於我們在發生錯誤時查找錯誤。
  爲了解決這種問題,於是Cpp中新誕生了四種更加直觀更加安全的類型轉換操作。

Cpp中的類型轉換

static_cast

  static_cast用於非多態類型的轉換(靜態轉換),編譯器隱式執行的任何類型轉換都可用static_cast,但它不能用於兩個不相關的類型進行轉換。

#include <iostream>
int main()
{
    double d = 10.2;
    int i = static_cast<int>(d);
    std::cout << "d:" << d << " i:" << i << std::endl;
}


d:10.2 i:10

  static_cast是一個模板函數,如上使用就可以完成類型的轉換,

#include <iostream>
int main()
{
    //double d = 10.2;
    //int i = static_cast<int>(d);
    //std::cout << "d:" << d << " i:" << i << std::endl;
    int i = 10;
    int *p = &i;
    int address = static_cast<int>(p);
}


invalid static_cast from type 'int*' to type 'int'

  但是如上的類型轉換就報錯了,說明static_cast是無法將int*轉爲int的,如果兩個類型毫無關係則無法進行轉換。

reinterpret_cast

  reinterpret_cast是一種十分危險的類型轉換,它用於指針,引用以及可以容納指針的整數類型之間的轉換,之所以說它危險是你甚至可以將一個類型指針任意轉換爲其他類型的指針,比如將int*轉換爲string*,於是這個指針的命運由此就徹底改變了,使用不當就內存訪問越界程序崩潰。

#include <iostream>
int main()
{
    int i = 10;
    double d;
    int* p = &i;
    //將指針強轉爲整形
    long long address = reinterpret_cast<long long>(p);
    std::cout << p << " " << address;
}


0x61fe0c 6422028

const_cast

  const_cast可以完成從const對象到non-const對象的轉換.

#include <iostream>
int main()
{
    const int i = 10;
    std::cout << i << std::endl;
    int& r = const_cast<int&>(i); 
    r = 11;
    std::cout << i << std::endl;
    std::cout << r << std::endl;
    const int a = 2;
    int *p = const_cast<int*>(&a);
    *p = 3;

    std::cout << a << std::endl;
    std::cout << *p << std::endl;
}

  經過類型強轉後我們發現確實可以更改指向常量的引用或指針了,但是通過輸出對比我們發現,引用和指針指向的數據被改變了但是原數據並沒有被改變,這是因爲編譯器的優化導致的,導致編譯器並沒有實際從內存中去取這塊內存,而是重新分配了一塊內存,我們可以使用volatile關鍵字來防止編譯器的優化。

dynamic_cast

  dynamic_cast可以完成從父類到子類的指針或者引用的強制類型轉換。從子類到父類的轉換我們有切割幫我們進行隱式類型轉換,但是從父類到子類是不能自動轉換的,我們只能通過dynamic_cast來強制轉換引用和指針,並且只能在有虛函數的類中進行轉換。dynamic_cast在轉換前會先進行轉換實驗,如果能轉換成功則轉換,轉換不成功則返回0。
  Cpp之所以可以完成類型的轉換,多虧與Cpp的RTTI機制,即運行時類型識別。雖然源文件中存儲着類型以及之間的繼承關係,但是其只用於編譯,在程序運行時是無法拿到這些信息,於是Cpp爲了可以在運行時獲取數據對象的類信息以及繼承關係便誕生了RTTIdynamic_casttypeidRTTI的典型應用。

#include <iostream>
class Parent
{
public:
    virtual void Func()
    {

    }
    int s = 10;
};
class Son : public Parent
{
public:
    int s = 11;
};
int main()
{
    Parent* p = new Parent;
    std::cout << p->s << std::endl;
    Son* s = dynamic_cast<Son*>(p);
    if(s == nullptr)
    {
        std::cout << "change error" << std::endl;
        return -1;
    }
    std::cout << s->s << std::endl;
}


11
change error

explicit

  這個參數之前已經在類和對象中講解過了,這個參數加在類的構造函數前用於禁用構造函數函數參數的隱式轉換。
  未禁用:

#include <iostream>
class Test
{
public:
    Test(int test)
        :_test(test)
    {
        std::cout << "construct" << std::endl;
    }
private:
    int _test;
};
int main()
{
    Test test = 10;
}



construct

  禁用:

#include <iostream>
class Test
{
public:
    explicit Test(int test)
        :_test(test)
    {
        std::cout << "construct" << std::endl;
    }
private:
    int _test;
};
int main()
{
    Test test = 10;//編譯不過
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章