1. 程式人生 > >C++學習之路(六):關於C++提供的強制類型轉換

C++學習之路(六):關於C++提供的強制類型轉換

code 記錄 是不是 通過 行修改 單元 c語言 enum 表達式

C語言中提供了舊式的強制類型轉換方法。比如:

int a =1;

char *p = (char *)&a;

上述將a的地址單元強制轉換為char類型的指針。這裏暫且不說上述轉換結果是否合理,但上述這樣的強制類型轉換,如果轉換過程出現問題,對於問題的追蹤與排查也比較困難。

對於C++而言,提供了較為安全的強制類型轉換方法,下面進行簡單介紹。

一、static_cast

對於任何具有明確定義的類型轉換,只要不包含底層const,都可以用static_cast。

主要可以有以下幾種轉換:

(1)用於基本數據類型之間的轉換,如把int轉換為char,把int轉換為enum,但這裏的轉換的安全性需要由開發者自己保證;

(2)把空指針轉換成目標類型的指針,這裏有點類似舊式的強制類型轉換的void*指針轉換,但同樣,對指針類型的解析,需要由開發者自己保證

(3)把任何類型的表達式類型轉換為void類型;

(4)用於類層次結構中父類和子類之間指針和引用的轉換。

上面的幾點後續遇到了樣例再進行補充,這裏給一個轉換void*指針的樣例說明。

代碼1:

int a = 1;
char *q = static_cast<char*>(&a);
cout<<*q<<endl;

上述代碼不能被編譯通過,因為static_cast對於指針的轉換,只能接受void*類型,上述&a依然是int型指針,不能通過編譯。

代碼2:

int a = 1;
char *q = static_cast<char*>((void *)&a);
cout<<*q<<endl;

通過將&a轉型為void*指針,完成對類型的強制轉換,上述代碼結果正常輸出。

二、const_cast

在由const關鍵字定義的變量,是不能在後續被修改的。比如:

  const int a = 1;

  a = 2;

上述編譯不通過,因為a不能被進行修改。

這裏我們依然先看一個樣例:

  

int func(int &a)
{
    return 0;
}

int main(void
) { const int a = 1; func(a); return 0; }

上述代碼中,a是一個const變量,但在func函數中的形參需要一個int型變量。很顯然,編譯直接報錯,因為實參與形參具有不同的類型。如何解決這個問題?這就需要引入const_cast進行類型轉換

const_cast只能改變運算對象的底層const。即對於一個const對象,const_cast可以將其const限定移除。上述代碼修改為:

int func(int *a)
{
    return 0;
}

int main(void)
{
    const int a = 1;
    int *p = const_cast<int*>(&a);
    func(p);
}

這裏將const的變量a的指針,強制類型轉換為非const的指針,在func中傳入指針變量,程序即可以成功編譯。

這裏就有一個疑問:如果可以const_cast將const變量轉換為非const變量,是否意味著,可以對const變量進行修改?如果可以,那是不是違背了const關鍵字的初衷? 這裏再看一個樣例代碼:

int main(void)
{
    const int a = 5;
    const int *p = &a;
    int *q = const_cast<int*>(p);
    
    cout<<&a<<endl;
    cout<<p<<endl;
    cout<<q<<endl;

    cout<<*q<<endl;
    *q = 6;
    cout<<*p<<endl;
    cout<<a<<endl;
    return 0;
}

a是一個const變量,p是一個const指針指向a,q通過const_cast強制類型轉換p得到一個非const指針。

直接貼出程序結果,再進行分析:

技術分享圖片

結果可以看到,&a,p,q的值都是相同的,證明p和q指針都正確指向了a的地址單元。接下來輸出*q,為a的原值5,再對*q進行了修改,輸出*p,結果為成功修改後的6。但最後輸出a變量,發現a變量依然為原值5。

結論很明顯了:對於const變量,仍然不能夠修改它本身的值,這是限定符自身的約束。

三、reinterpret_cast

關於reinterpret_cast,感覺更比較貼合舊式的強制類型轉換。舉個例子:

int a = 1;
char *q = reinterpret_cast<char*>(&a);
cout<<*q<<endl;

上述對於static_cast的使用,需要對&a轉換為void*才能夠進行,但使用reinterpret_cast則可以直接進行轉換。reinterpret_cast本質上依賴於機器。

四、dynamic_cast

關於dynamic_cast,用法比較豐富,會再之後進行討論。

結論:對於一條強制類型轉換的語句,都應該反復斟酌是否能用其他方式來實現相同的目標,就算實在無法避免,也應用盡量限制類型轉換值的作用域,並記錄對相關類型的所有假定,這樣可以減少錯誤發生的機會。

C++學習之路(六):關於C++提供的強制類型轉換