C++超詳細(xì)講解強(qiáng)制類型轉(zhuǎn)換的用法
static_cast
static_cast<type-id>(expression)
將 expression 轉(zhuǎn)換為 type-id 類型。static_cast 是靜態(tài)類型轉(zhuǎn)換,發(fā)生在編譯期。這種轉(zhuǎn)換不會進(jìn)行運(yùn)行時的動態(tài)檢查(RTTI),因而這種轉(zhuǎn)換可能是不安全的。static_cast 典型應(yīng)用場景如下:
1. 類的層級結(jié)構(gòu)中,基類和子類之間指針或者引用的轉(zhuǎn)換。
上行轉(zhuǎn)換(Upcasting),也即子類像基類方向轉(zhuǎn)換,是安全的。
下行轉(zhuǎn)換(Downcasting),也即基類向子類方向轉(zhuǎn)換,是不安全的,需要程序員自行保證安全轉(zhuǎn)換。
下面舉例說明:
class A {
public:
virtual void func() {
std::cout << "A::func()" << std::endl;
}
};
class B : public A {
public:
virtual void func() {
std::cout << "B::func()" << std::endl;
}
void print() {
std::cout << "B::print()" << std::endl;
}
};
對于上行轉(zhuǎn)換,肯定是安全的。
B* pb = new B(); A* pa = static_cast<A*>(pa); pa->func();
對于下行轉(zhuǎn)換:
A* pa = new B(); B* pb = static_cast<B*>(pa); pb->print();
這里,A* pa = new B();,由于 C++ 的多態(tài)的支持,可以使用基類指針指向子類。這里的轉(zhuǎn)換是安全的,因為 pa 初始化就指向的就是 B。而下面的轉(zhuǎn)換則是不安全的:
A* pa = new A(); B* pb = static_cast<B*>(pa); pb->print();
此外,對于兩個不存在繼承關(guān)系的兩個類之間轉(zhuǎn)換,總是失敗的,編譯器報錯:
#include <iostream>
class A {
virtual void func(){}
};
class B {
virtual void func(){}
};
int main(){
A* pa = new A();
B* pb = static_cast<B*>(pa);
return 0;
}2. 基本數(shù)據(jù)類型間的轉(zhuǎn)換。這種轉(zhuǎn)換也是不安全的,需要程序員自行保證安全轉(zhuǎn)換。 例如 int 轉(zhuǎn) short,直接高位截斷;而 short 轉(zhuǎn) int 則高位根據(jù)符號位填充。兩種不同類型指針間相互轉(zhuǎn)換是相當(dāng)危險的,例如 int* 轉(zhuǎn) float*。將 int 轉(zhuǎn)換為指針類型也是危險的轉(zhuǎn)換,例如 float* p = static_cast<float*>(0X2edf);
3. 將 void 類型轉(zhuǎn)換為其他類型的指針。 顯然這種轉(zhuǎn)換也是不安全的,需要程序員自行保證安全轉(zhuǎn)換。
4. 把其他類型轉(zhuǎn)換為 void 類型。
有轉(zhuǎn)換構(gòu)造函數(shù)或者類型轉(zhuǎn)換函數(shù)的類與其它類型之間的轉(zhuǎn)換。例如:
#include <iostream>
class Point{
public:
Point(double x, double y): m_x(x), m_y(y){ }
Point(double& x): m_x(x), m_y(1.1){ }
public:
operator double() const { return m_x; } //類型轉(zhuǎn)換函數(shù)
void print() {
std::cout << "m_x: " << m_x << " m_y: " << m_y << std::endl;
}
private:
double m_x;
double m_y;
};
int main() {
Point p1(12.5, 23.8);
double x= static_cast<double>(p1);
// std::cout << x << std::endl;
Point p2 = static_cast<Point>(x);
// p2.print();
return 0;
}dynamic_cast
dynamic_cast<type-id>(expression)
把 expression 轉(zhuǎn)換為 type-id 類型,type-id 必須是類的指針、類的引用或者是 void *;如果 type-id 是指針類型,那么 expression 也必須是一個指針;如果 type-id 是一個引用,那么 expression 也必須是一個引用。
dynamic_cast 提供了運(yùn)行時的檢查。對于指針類型,在運(yùn)行時會檢查 expression 是否真正的指向一個 type-id 類型的對象,如果是,則能進(jìn)行正確的轉(zhuǎn)換;否則返回 nullptr。對于引用類型,若是無效轉(zhuǎn)換,則在運(yùn)行時會拋出異常 std::bad_cast。
T1 obj; T2* pObj = dynamic_cast<T2*>(&obj); // 無效轉(zhuǎn)換返回 nullptr T2& refObj = dynamic_cast<T2&>(obj); // 無效轉(zhuǎn)換拋出 bad_cast 異常
上行轉(zhuǎn)換:其實和 static_cast 是一樣的,一般肯定能成功。例如前面用到的例子:
// A->B B* pb = new B(); A* pa = static_cast<A*>(pa);
但是,下面這種繼承關(guān)系會轉(zhuǎn)換失?。?/p>
#include <iostream>
/* A
/ \
V V
B C
\/
v
D */
class A {
virtual void func(){}
};
class B : public A {
void func(){}
};
class C : public A {
void func(){}
};
class D : public B, public C {
void func(){}
};
int main(){
D* pd = new D();
A* pa = dynamic_cast<A*>(pd);
return 0;
}上面這個例子,雖然也是上行轉(zhuǎn)換,但是存在兩條路徑,在 B 和 C 都繼承于 A,并且有虛函數(shù)實現(xiàn),上行轉(zhuǎn)換不知道從哪條路徑進(jìn)行轉(zhuǎn)換。下面的寫法則沒問題:
D* pd = new D(); B* pb = dynamic_cast<B*>(pd); A* pa = dynamic_cast<A*>(pb);
下行轉(zhuǎn)換:看個例子。
#include <iostream>
class A {
virtual void func(){}
};
class B : public A {
void func(){}
};
int main(){
A* pa1 = new B();
A* pa2 = new A();
B *pb1 = dynamic_cast<B*>(pa1); // ok
B *pb2 = dynamic_cast<B*>(pa2); // pb2 is a nullptr!
return 0;
}其實 dynamic_cast 本質(zhì)只支持上行轉(zhuǎn)換,只會沿著繼承鏈向上遍歷,找到目標(biāo)類型則轉(zhuǎn)換成功,否則失敗。dynamic_cast 看似支持下行轉(zhuǎn)換,這都是多態(tài)的緣故。上面的例子,pa1 雖然類型是 A,但實際指向 B,沿著 B 向上可以找到 B,因為第一個轉(zhuǎn)換可以成功。而 pa2 指向 A,沿著 A 向上找不到 B 類型,因而轉(zhuǎn)換失敗。
因而在有繼承關(guān)系的類的轉(zhuǎn)換時候, static_cast 轉(zhuǎn)換總是成功的, dynamic_cast 顯然比 static_cast 更加安全。
const_cast
const_cast 用來去掉表達(dá)式的 const 修飾或 volatile 修飾,也就是將 const 或 volatile 類型轉(zhuǎn)換為非 const 或 非 volatile 類型。
#include <iostream>
int main(){
const int n = 111;
int *p = const_cast<int*>(&n);
*p = 222;
std::cout<< "n = " << n << std::endl;
std::cout<< "*p = " << *p << std::endl;
return 0;
}
這里需要注意:按照正常理解,n 的打印值應(yīng)該是 222。但是,由于編譯器的常量傳播優(yōu)化,std::cout<< "n = " << n << std::endl; 會被編譯器替換成類似 std::cout<< "n = " << 111 << std::endl; 的語義。
reinterpret_cast
reinterpret_cast 轉(zhuǎn)換直接對二進(jìn)制位按照目標(biāo)類型重新解釋,非常粗暴,所以風(fēng)險很高,慎重使用。
#include <iostream>
int main(){
char str[]="hello world!";
float *p = reinterpret_cast<float*>(str);
std::cout << *p << std::endl; // 1.14314e+27
return 0;
}到此這篇關(guān)于C++超詳細(xì)講解強(qiáng)制類型轉(zhuǎn)換的用法的文章就介紹到這了,更多相關(guān)C++強(qiáng)制類型轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++中的強(qiáng)制類型轉(zhuǎn)換操作詳解
- C++超詳細(xì)講解強(qiáng)制類型轉(zhuǎn)換
- C++強(qiáng)制類型轉(zhuǎn)換的四種方式
- C++ 強(qiáng)制類型轉(zhuǎn)換詳解
- C++中4種強(qiáng)制類型轉(zhuǎn)換的區(qū)別詳析
- 關(guān)于C++的強(qiáng)制類型轉(zhuǎn)換淺析
- C++中4種強(qiáng)制類型轉(zhuǎn)換的區(qū)別總結(jié)
- 深入C++四種強(qiáng)制類型轉(zhuǎn)換的總結(jié)
- C++類的自動轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換的實現(xiàn)示例
相關(guān)文章
C++實現(xiàn)十六進(jìn)制字符串轉(zhuǎn)換成int整形值的示例
今天小編就為大家分享一篇關(guān)于C++實現(xiàn)十六進(jìn)制字符串轉(zhuǎn)換成int整形值的示例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12
利用C++開發(fā)一個protobuf動態(tài)解析工具
數(shù)據(jù)庫中存儲的protobuf序列化的內(nèi)容,有時候查問題想直接解析查看內(nèi)容。很多編碼在網(wǎng)上很容易找到編解碼工具,但protobuf沒有找到編解碼工具,可能這樣的需求比較少吧,那就自己用C++實現(xiàn)一個,感興趣的可以了解一下2023-01-01

