1. 程式人生 > >C++小點之四種強制型別轉換

C++小點之四種強制型別轉換

提問:

1.為什麼要搞出四種,用原先使用的那種不可以嗎?

答:因為強制型別轉換時是具有一定的風險的,這種風險包括(精度的損失 ,派生類與基類的一些轉換關係) 而且根據風險程度的不同導致的 bug 也會不同 ,再加上存在許多種型別之間的轉換 ,
所以C++選擇將其分為四種 。

2.這樣分類之後又有什麼好處吶?

答:關於這個問題,讓我們來設想一個場景。假如你現在知道你的bug 是因為指標型別之間的轉換所導致的 ,那你現在就必須得定位它/它們 ,如果還用以前的那種方式,就會找到許多無關於這次需求的東西,如果使用C++的這種方式,你只需要去找所對應的 _cast 就行了 。很方便吧 :)

四種強制型別轉換:static_cast , interpret_cast ,const_cast和 dynamic_cast

(1)static_cast

<1>適用:用來進行比較“自然”和低風險的轉換 。比如:整型與實數,字元型之間的轉換

<2>不適用:不同型別指標,整型與指標,不同型別引用之間的轉換 。

#include<iostream>
using namespace std;
class A
{
public:
    operator int(){return 1 ;} //注意這裡!!!!
    operator char *(){return
nullptr ;} }; int main(int argc, char const *argv[]) { A a ; int n ; char *p= "Liu Shengxi "; n= static_cast<int>(3.14); // 3 cout << n << endl ; n = static_cast<int>(a) ; // 1 cout << n << endl ; p = static_cast<char *>(a);/*從型別‘int’到型別‘char*’中的 static_cast 無效*/
return 0; }

(2)interpret_cast

<1>適用:用來進行各種不同型別的指標,引用,以及指標和能容納的下指標的整數型別之間的轉換。轉換方式:逐個拷貝位元

#include<iostream>
using namespace std ;
class A
{
public:
    int i ;
    int j ; 
    A(int n):i(n),j(n){}
};
int main(int argc, char const *argv[])
{
    A a(100);
    int &r = reinterpret_cast<int &>(a);//引用之間的轉換
    r =  200 ; 
    cout << a.i <<" ," << a.j << endl ;
    int n = 300 ; 
    A *pa =reinterpret_cast< A *>(& n);
    pa-> i = 400 ; // n 變為 400 
    pa->j = 500 ; //不安全,容易導致程式崩潰
    cout << "n== " << n << endl ;

    typedef void (*PF1)(int) ;
    typedef int (*PF2)(int ,char *);
    PF1 pf1  ;
    PF2 pf2 ;
    pf2 = reinterpret_cast<PF2>(pf1 );//不同型別的函式指標也可以互相轉換
    return 0;
}

<2>不適用:

(3)const_cast

<1>適用:用來去除const 屬性 ,將const 引用或者const 指標轉換為同類型的非const型別 。

<2>不適用:

const string s= "TT";
string &p = const_cast<string &>(s) ;
string *pp = const_cast<string *>(&s) ;//&s 就是const string * 

(4)dynamic_cast

<1>適用:專門用於將多型基類(包含虛擬函式的基類)的指標/引用強制轉換為派生類指標/引用 。而且能夠檢查轉換的安全性。對於不安全的指標轉換,返回 NULL指標。

<2>不適用:

#include<iostream>
using namespace std;
class Base
{
    public:
    virtual ~Base(){} //有虛擬函式,所以是多型基類
};
class Derived:public Base
{  
};
int main(void){
    Base b; 
    Derived d ;
    Derived *pd ;
    pd = reinterpret_cast<Derived *>(&b ) ; //reinterpret_cast 不檢查安全性,總是進行轉換
    if(pd == NULL ) 
        cout << "1111 " << endl; 

    pd = dynamic_cast<Derived *>(&b ); //轉換會失敗 ,因為&b 並沒有實際指向一個派生類物件 
    if(pd == NULL )
        cout << "unsafe dynamic_cast  " << endl; 
    Base *pb = &d ;

    pd = reinterpret_cast<Derived *>(pb );//成功
    if(pd == NULL )
        cout << "unsafe dynamic_cast  " << endl; 
    else 
        cout << "safe dynamic_cast  " << endl; 
    return 0 ;
}

總結:

1.基類指標向派生類指標的轉換取決於這個基類指標是不是真的指向一個派生類物件 ,如果是,那轉換之後完全OK,如果不是,那麼將它強制轉換為派生類指標時就會出現問題 。

2. 關於指標的有dynamic_cast 和 interpret_cast 。其中dynamic_cast 只用於多型基類

3. const_cast 用來去除const 屬性

4. static_cast 無關於指標和引用