在C語言中,強制類型的轉換方式很簡單,通過Type a = (Type)b
即可,但是這樣有兩個比較明顯的缺點:一是轉換方式過於隨意,可以在指針和整數之間進行轉換,這是比較危險的操作;二是這樣的轉換方式在多括號的情況下不夠清晰和直接,進而C++推出了自己的轉換方式來改善這兩種情況。C++顯式類型轉換有四種const_cast、static_cast、dynamic_cast、reinterpreter_cast,四種轉換方式各有用途,需要針對不同情況選取不同的轉換方式。
static_cast
static_cast是一種最常用的轉型方式,我們可以在日常轉型操作中首先嘗試使用它,可能在很多場景中不需要它也能夠隱式的完成轉型操作,但是我們還是盡可能的將轉型操作顯式的表現出來。
可以完成以下類型的轉換
- 基本類型的轉換(char轉int,int轉float之類)
- void類型空指針轉其他類型空指針
- 任意類型轉void類型指針
- 父類到子類的轉換(不保證正確)
- 子類到父類的轉換(保證正確)
注意:static_cast不能轉換掉expression的const、volatile、或者__unaligned屬性
const_cast
用於將const變量轉換為非const變量,這是其他任何轉換類型所沒有的功能。需要注意兩個點
- 去除const屬性不是對於最初的const對象來說,修改最初的const對象仍舊是未定義的,去除const屬性是指從引用或指針的方式來去除const屬性。
- const_cast只適用於指針或者引用方式
#include <iostream>
using namespace std;
class A
{
public:
void print() { cout << "hello" << endl; }
void print() const { cout << "world" << endl; }
};
int main(){
const int a=100;
cout << &a << " : " << a << endl;
int &b = const_cast<int&>(a);
b = 110;
cout << &b << " : " << b << endl;
int *pa = const_cast<int*>(&a);
*pa = 120;
cout << pa << " : " << *pa << endl;
cout << &a << " : " << a << endl;
cout << &b << " : " << b << endl;
A a;
a.print();
const A b;
b.print();
A& ref = const_cast<A&>(b);
A* ptr = const_cast<A*>(&b);
ref.print();
ptr->print();
}
輸出:
0x7ffcd8468304 : 100
0x7ffcd8468304 : 110
0x7ffcd8468304 : 120
0x7ffcd8468304 : 100
0x7ffffe03f164 : 120
hello
world
hello
hello
這里明明地址一樣,為什么a和b,*pa的值會不一樣呢?
答:a其實用const修飾后是一個常量,在預編譯階段,常量會被真實數值替換,所以並不是cout << a << endl;而是cout << 100 << endl;
dynamic_cast
dynamic_cast轉換主要用於多態方面的轉換,例如父類與子類之間的互相轉換。在轉換過程中如果能夠成功轉換就返回目標類型的指針,如果不行的話就返回空指針(用指針方式轉換)或者拋出異常(用引用方式轉換)。在進行upcast時,static_cast和dynamic_cast具有相同的效果;但在downcast(向下轉換,也就是父類向子類轉換)時,dynamic_cast相對於static_cast有一個類型檢查,相對來說更加安全。另外需要注意的是:
- 如果子類不是通過public繼承父類的話,那么轉換會失敗。這是因為父類的public成員因為private繼承變成了private屬性(對於子類而言),子類的指針無法訪問父類中的非private成員,就會出現轉換失敗的問題
class A {
private:
int a;
public:
A(int a_) :a(a_) {}
virtual void vprintfself(void) {
std::cout <<"a"<<this->a<<std::endl;
}
};
class B: public A {
private:
int b;
public:
B(int a_,int b_) :A(a_) { b = b_; }
void vprintfself(void) {
std::cout <<"b "<<this->b<< std::endl;
}
};
int main()
{
A* a = new A(2);
B* static_p_a_B = static_cast<B*>(a);
B* dymatic_p_a_B =dynamic_cast<B*>(a);//空指針
static_p_a_B->vprintfself();
dymatic_p_a_B->vprintfself();//報錯
}
reinterpret_cast
interpret是解釋的意思,reinterpret即為重新解釋。這個轉換幾乎沒什么條件限制,可以將任何指針類型轉化為其他指針類型,少用為佳。
參考: