C++小點之四種強制型別轉換
阿新 • • 發佈:2019-02-11
提問:
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 ;
}