C++中的Cast
引言
在一次看More Effective C++中,有一節提到了《Prefer C++-Style Casts》。其中列舉許多C++ Cast的一些好處,當然這些都是相對於C語言中的強制轉換這類而言的。
所以首先來了解C++中的Cast。
一、Dynamic_Cast
我們從適用範圍來了解這個操作。
(1)首先dynamic_cast能夠應用於指針轉換。
子類指針轉換成父類指針,成功;
父類指針轉換成子類指針,就分爲兩種情況:
<a>父類指針p如果真的指向子類對象,那麼轉換時成功的;
<b>反之,失敗,dynamic_cast返回NULL。
(2)其次dynamic_cast能夠應用與引用之間的轉換(與指針類似)。
子類引用轉換成父類引用,成功;
父類引用轉換成子類引用,就分爲兩種情況:
<a>父類引用ob,如果真的指向子類對象,那麼轉換時成功的;
<b>反之,失敗,dynamic_cast,會拋出bad_cast異常
(3)其他將null指針,轉換成任何類型的指針;將任何類型的指針轉換成void*類型的指針。
參考代碼:
class CBase
{
protected:
int m_data;
public:
virtual void fun(){}
};
class CSub1 : publicCBase
{
protected:
intm_data_a;
};
class CSub2 : publicCBase
{
protected:
longm_data_b;
};
//////////////////////////////////////////////////////////////////////////
void test_dynamic_cast()
{
CBase * pb = newCBase();
CSub1 * p1 = newCSub1();
charstrTrue[] = "true";
charstrFalse[] = "false";
//cast a class toits base class
CBase * p = dynamic_cast<CBase*>(p1);
cout<<"dynamic_cast<CBase *>(p1); is ok? "<< ((p != NULL) ? "true" : "false")<<endl;
//cast a class toits derived class
CSub1 * pSub1 = dynamic_cast<CSub1*>(pb);
cout<<"dynamic_cast<CSub1 *>(pb); is ok? "<< ((pSub1 != NULL)? "true" : "false") <<endl;
delete pb;
delete p1;
//
try
{
CBase obb;
CSub1 obsub1;
CBase & ob1 = dynamic_cast<CBase &>(obsub1);
CSub1 & ob2 = dynamic_cast<CSub1 &>(obb);
}
catch(bad_cast e)
{
}
}
二、Static_Cast
Static_cast可以轉換相關聯的類,可以從子類轉換成父類。也能從父類轉向子類,但是如果轉換的父類指針(或者父類引用)所指向的對象是完整的,那麼是沒有問題;但是如果所指向的對象並不完整,那麼會出現runtime錯誤。
Static_cast相對於dynamic_cast而言,除了能轉換指針和引用,還能應用於任何能夠隱式轉換的情況。比如下面的情況。
void test_static_cast()
{
float f =1.012;
int i = static_cast<int>(f);
}
三、Reinterpret_Cast
reinterpret_cast和上面講到的兩個cast,適用範圍更加廣泛。它可以適用於任何類型指針之間的轉換。
該操作不會去進行動態類型或者靜態類型的檢測,它僅僅將值強行賦值過去。從某種意義上對編譯器進行了一種欺騙,同時也帶來了一定的不安全性。所以在使用這個cast的時候,要慎重。下面是這個操作的適用情況:
(1) Int和指針之間的相互轉換;
(2) 無關聯類指針之間的轉換;
(3) 函數指針之間的轉換
下面是這個操作的使用實例:
class A
{
public:
A(inti):m_data(i){}
int m_data;
};
class B
{
public:
B(floatf):m_data(f){}
floatm_data;
};
class C
{
public:
C(long long ll):m_date(ll){}
long long m_date;
};
void test_reinterpret_cast()
{
A * pa = newA(1);
B * pb = newB(1.12);
C * pc = newC(121321312321);
//
A * p1 = reinterpret_cast<A*>(pb);
cout<<" reinterpret_cast<A *>(pb); is ok?"<< ((p1 != NULL) ? "true": "false") <<endl;
cout<<p1->m_data<<endl;
p1 = reinterpret_cast<A*>(pc);
cout<<" reinterpret_cast<A *>(pc); is ok?"<< ((p1 != NULL) ? "true": "false") <<endl;
cout<<p1->m_data<<endl;
//
delete pa;
delete pb;
delete pc;
}
結果:
四、Const_Cast
const_cast如它的名字,它是去除修飾在對象上的const和volatile。
五、總結
這裏借用more effective c++中的觀點:隱式轉換,在代碼中很難尋找;但是使用C++的這種cast可以輕鬆的找出,代碼中哪裏使用強制轉換等。去除了c語言中轉換之間的惡習,將它們規範成了幾個operator。