有什么做服裝的網(wǎng)站蘭州seo網(wǎng)站建設(shè)
理解C++強(qiáng)制類型轉(zhuǎn)換
文章目錄
- 理解C++強(qiáng)制類型轉(zhuǎn)換
- 理解C++強(qiáng)制轉(zhuǎn)換運(yùn)算符
- 1 static_cast
- 1.1. static_cast用于內(nèi)置數(shù)據(jù)類型之間的轉(zhuǎn)換
- 1.2 用于指針之間的轉(zhuǎn)換
- 1.3 用于基類與派生類之間的轉(zhuǎn)換
- 2. const_cast
- 2.1示例1
- 2.2 示例2——this指針
- 3.reinterpret_cast
- 4.dynamic_cast
- C++認(rèn)為C風(fēng)格的類型轉(zhuǎn)換過(guò)于松散,可能會(huì)帶來(lái)隱患,不夠安全。
- C++推出了新的類型轉(zhuǎn)換來(lái)替代C風(fēng)格的類型轉(zhuǎn)換,采用更嚴(yán)格的語(yǔ)法檢查,降低使用風(fēng)險(xiǎn)。
- C++新增了四個(gè)關(guān)鍵字static_cast、const_cast、reinterpret_cast和dynamic_cast,用于支持C++風(fēng)格的類型轉(zhuǎn)換。
- C++的類型轉(zhuǎn)換只是語(yǔ)法上的解釋,本質(zhì)上與C風(fēng)格的類型轉(zhuǎn)換沒(méi)什么不同,C語(yǔ)言做不到事情的C++也做不到。
C語(yǔ)言強(qiáng)制類型轉(zhuǎn)換是有一定風(fēng)險(xiǎn)的,有的轉(zhuǎn)換并不一定安全,如
- 把整型數(shù)值轉(zhuǎn)換成指針;
- 把基類指針轉(zhuǎn)換成派生類指針;
- 把一種函數(shù)指針轉(zhuǎn)換成另一種函數(shù)指針;
- 把常量指針轉(zhuǎn)換成非常量指針等。
總結(jié):C語(yǔ)言強(qiáng)制類型轉(zhuǎn)換缺點(diǎn);主要是為了克服C語(yǔ)言強(qiáng)制類型轉(zhuǎn)換的以下三個(gè)缺點(diǎn)。
- 沒(méi)有從形式上體現(xiàn)轉(zhuǎn)換功能和風(fēng)險(xiǎn)的不同。
- 將多態(tài)基類指針轉(zhuǎn)換成派生類指針時(shí)不檢查安全性,即無(wú)法判斷轉(zhuǎn)換后的指針是否確實(shí)指向一個(gè)派生類對(duì)象。
- 難以在程序中尋找到底什么地方進(jìn)行了強(qiáng)制類型轉(zhuǎn)換強(qiáng)制類型轉(zhuǎn)換是引發(fā)程序運(yùn)行時(shí)錯(cuò)誤的一個(gè)原因,因此在程序出錯(cuò)時(shí),可能就會(huì)想到是不是有哪些強(qiáng)制類型轉(zhuǎn)換出了問(wèn)題。
例如,將int 強(qiáng)制轉(zhuǎn)換成 double是沒(méi)有風(fēng)險(xiǎn)的,而將常量指針轉(zhuǎn)換成非常量指針,將基類指針轉(zhuǎn)換成派生類指針都是高風(fēng)險(xiǎn)的,而且后兩者帶來(lái)的風(fēng)險(xiǎn)不同(即可能引發(fā)不同種類的錯(cuò)誤),C語(yǔ)言的強(qiáng)制類型轉(zhuǎn)換形式對(duì)這些不同并不加以區(qū)分
舉例1. 把整型數(shù)值轉(zhuǎn)換成指針,編譯階段不報(bào)錯(cuò),運(yùn)行階段報(bào)錯(cuò)
理解C++強(qiáng)制轉(zhuǎn)換運(yùn)算符
C++ 引入了四種功能不同的強(qiáng)制類型轉(zhuǎn)換運(yùn)算符以進(jìn)行強(qiáng)制類型轉(zhuǎn)換
- static cast
- const cast
- reinterpret_cast
- dynamic_cast
語(yǔ)法:(目標(biāo)類型)表達(dá)式或目標(biāo)類型(表達(dá)式);
- static_cast<目標(biāo)類型>(表達(dá)式);
- const_cast<目標(biāo)類型>(表達(dá)式);
- reinterpret_cast<目標(biāo)類型>(表達(dá)式);
- dynamic_cast<目標(biāo)類型>(表達(dá)式);
1 static_cast
1.1. static_cast用于內(nèi)置數(shù)據(jù)類型之間的轉(zhuǎn)換
用途:基本等價(jià)于隱式轉(zhuǎn)換的一種類型轉(zhuǎn)換運(yùn)算符,可使用于需要明確隱式轉(zhuǎn)換的地方。
可以用于低風(fēng)險(xiǎn)的轉(zhuǎn)換
- 整型和浮點(diǎn)型
- 字符與整形
- 轉(zhuǎn)換運(yùn)算符
- *空指針轉(zhuǎn)換為任何目標(biāo)類型的指針
不可以用與風(fēng)險(xiǎn)較高的轉(zhuǎn)換
- 不同類型的指針之間互相轉(zhuǎn)換
- 整型和指針之間的互相轉(zhuǎn)換
- 不同類型的引用之間的轉(zhuǎn)換
#include <iostream>
using namespace std;
class CInt
{
public:operator int(){this->m_Int = 128;return m_Int;}
int m_Int;};
int main(int argc, char* argv[])
{int i = 3;float f = 10.0f;f = i; //可以隱式轉(zhuǎn)換,會(huì)出現(xiàn)警告int”轉(zhuǎn)換到“float”,可能丟失數(shù)據(jù) long m = i; // 絕對(duì)安全,可以隱式轉(zhuǎn)換,不會(huì)出現(xiàn)警告。double dd = 1.23;long m1 = dd; // 可以隱式轉(zhuǎn)換,會(huì)出現(xiàn)可能丟失數(shù)據(jù)的警告。long m2 = (long)dd; // C風(fēng)格:顯式轉(zhuǎn)換,不會(huì)出現(xiàn)警告。long m3 = static_cast<long>(dd); // C++風(fēng)格:顯式轉(zhuǎn)換,不會(huì)出現(xiàn)警告。cout << "m1=" << m1 << ",m2=" << m2 << ",m3=" << m3 << endl;//低風(fēng)險(xiǎn)的轉(zhuǎn)換:整型與浮點(diǎn)型;字符型與整型;void *指針轉(zhuǎn)換為任意類型指針//字符型與整型char ch='a';int n = 5;n = static_cast<int>(ch);//void *指針轉(zhuǎn)換為任意類型指針void *p = nullptr;int *p1 = static_cast<int *>(p);//轉(zhuǎn)換運(yùn)算符,類與其他類型CInt Obj;//int k=Obj ;//可以隱式轉(zhuǎn)換int k = static_cast<int>(Obj);cout << "k=" << k << endl;}
1.2 用于指針之間的轉(zhuǎn)換
C風(fēng)格可以把不同類型的指針進(jìn)行轉(zhuǎn)換。
C++不可以,需要借助void *。
#include <iostream>
using namespace std;
class CInt
{
public:operator int(){this->m_Int = 128;return m_Int;}
int m_Int;};
int main(int argc, char* argv[])
{int i = 3;float f = 10.0f;f = i; //可以隱式轉(zhuǎn)換,會(huì)出現(xiàn)警告int”轉(zhuǎn)換到“float”,可能丟失數(shù)據(jù) long m = i; // 絕對(duì)安全,可以隱式轉(zhuǎn)換,不會(huì)出現(xiàn)警告。double dd = 1.23;long m1 = dd; // 可以隱式轉(zhuǎn)換,會(huì)出現(xiàn)可能丟失數(shù)據(jù)的警告。long m2 = (long)dd; // C風(fēng)格:顯式轉(zhuǎn)換,不會(huì)出現(xiàn)警告。long m3 = static_cast<long>(dd); // C++風(fēng)格:顯式轉(zhuǎn)換,不會(huì)出現(xiàn)警告。cout << "m1=" << m1 << ",m2=" << m2 << ",m3=" << m3 << endl;//低風(fēng)險(xiǎn)的轉(zhuǎn)換:整型與浮點(diǎn)型;字符型與整型;void *指針轉(zhuǎn)換為任意類型指針//高風(fēng)險(xiǎn)的轉(zhuǎn)換:整型與指針類型轉(zhuǎn)換//字符型與整型char ch='a';int n = 5;n = static_cast<int>(ch);//void *指針轉(zhuǎn)換為任意類型指針void *p = nullptr;int *p1 = static_cast<int *>(p);//轉(zhuǎn)換運(yùn)算符,類與其他類型CInt Obj;//int k=Obj ;//可以隱式轉(zhuǎn)換int k = static_cast<int>(Obj);cout << "k=" << k << endl;//}
1.3 用于基類與派生類之間的轉(zhuǎn)換
int main()
{CFather* pFather = nullptr;CSon* pSon = nullptr;//父類轉(zhuǎn)子類(不安全)//pSon = pFather;pSon = static_cast<cson*>(pFather); //不安全,沒(méi)有提供運(yùn)行時(shí)的檢測(cè),編譯會(huì)通過(guò)//子類轉(zhuǎn)父類(安全)pFather = pSon;pFather = static cast<CFather*>(pSon);}
2. const_cast
- static_cast不能丟掉指針(引用)的const和volitale屬性,const_cast可以。
- 僅用于進(jìn)行去除
const
屬性的轉(zhuǎn)換,它也是四個(gè)強(qiáng)制類型轉(zhuǎn)換運(yùn)算符中唯一能夠去除const
屬性的運(yùn)算符。 - const_cast 只針對(duì)指針,引用,this指針
2.1示例1
示例1改為
#include <iostream>
#include <string>
int main()
{const int n = 5;const std::string s = "Inception";//const_cast 只針對(duì)指針,引用,this指針int *k = const_cast<int*>(&n);//const_cast<int*>指針類型 &n取出變量地址*k = 123456;std::cout <<"改變后的值 "<< *k << std::endl;}
#include <iostream>
#include <string>
int main()
{const int n = 5;const std::string s = "Inception";//const_cast 只針對(duì)指針,引用,this指針int *k = const_cast<int*>(&n);//const_cast<int*>指針類型 &n取出變量地址int &k1 = const_cast<int&>(n);//const_cast<int&>引用類型 *k = 123456;k1 = 10000;std::cout <<"改變后的值 "<< *k << std::endl;std::cout << "改變后的值 " << k1 << std::endl;
}
2.2 示例2——this指針
常成員函數(shù)——不能修改成員變量的值,使用const_cast
讓常成員函數(shù)可以修改成員變量的值,這個(gè)做法感覺(jué)有點(diǎn)無(wú)聊
#include <iostream>
#include <string>
class CTest
{
public:int m_test=100;void foo(int test) const{//m_test = test;//void *p = this;const_cast<CTest* const>(this)->m_test = test;//const_cast<const CTest* const>(this)->m_test = test;//報(bào)錯(cuò)}
};int main()
{int n = 5;int* const p=&n;//p = 0x123;CTest t;t.foo(1);std::cout << t.m_test << std::endl;//const int n = 5;//const std::string s = "Inception";const_cast 只針對(duì)指針,引用,this指針//int *k = const_cast<int*>(&n);//const_cast<int*>指針類型 &n取出變量地址//int &k1 = const_cast<int&>(n);//const_cast<int&>引用類型 //*k = 123456;//k1 = 10000;//std::cout <<"改變后的值 "<< *k << std::endl;//std::cout << "改變后的值 " << k1 << std::endl;
}
3.reinterpret_cast
static_cast不能用于轉(zhuǎn)換不同類型的指針(引用)(不考慮有繼承關(guān)系的情況),reinterpret_cast可以。
reinterpret_cast的意思是重新解釋,能夠?qū)⒁环N對(duì)象類型轉(zhuǎn)換為另一種,不管它們是否有關(guān)系。
語(yǔ)法:reinterpret_cast<目標(biāo)類型>(表達(dá)式);
<目標(biāo)類型>和(表達(dá)式)中必須有一個(gè)是指針(引用)類型。
reinterpret_cast不能丟掉(表達(dá)式)的const或volitale屬性。
應(yīng)用場(chǎng)景:
1)reinterpret_cast的第一種用途是改變指針(引用)的類型。
2)reinterpret_cast的第二種用途是將指針(引用)轉(zhuǎn)換成整型變量。整型與指針占用的字節(jié)數(shù)必須一致,否則會(huì)出現(xiàn)警告,轉(zhuǎn)換可能損失精度。
3)reinterpret_cast的第三種用途是將一個(gè)整型變量轉(zhuǎn)換成指針(引用)。
示例:
#include <iostream>
using namespace std;void func(void* ptr) { long long ii = reinterpret_cast<long long>(ptr);cout << "ii=" << ii << endl;
}int main(int argc, char* argv[])
{long long ii = 10;func(reinterpret_cast<void *>(ii));
}
4.dynamic_cast
動(dòng)態(tài)轉(zhuǎn)換(dynamic_cast)用于基類和派生類之間的轉(zhuǎn)換,但只能在運(yùn)行時(shí)確定類型信息,因此只能用于多態(tài)類型。如果轉(zhuǎn)換失敗,將返回一個(gè)null指針。其語(yǔ)法如下:
dynamic_cast<目標(biāo)類型> (原始類型)
以下是幾個(gè)具體例子:
1、將一個(gè)基類指針強(qiáng)制轉(zhuǎn)換為一個(gè)派生類指針:
class Base { virtual void f(){} };
class Derived : public Base { void f(){} };
Base *b = new Derived(); // 基類指針指向派生類對(duì)象
Derived *p = dynamic_cast<Derived *>(b); // 將基類指針轉(zhuǎn)換為派生類指針
2、使用 dynamic_cast 對(duì)指針進(jìn)行類型判斷:
class Base {};
class Derived : public Base {};Base* b1 = new Derived();
Derived* d1 = dynamic_cast<Derived*>(b1);
if (d1 != nullptr) {// b1 是 Derived 類型的。
}
需要注意的是,如果指向的基類指針并不真正指向派生類,或者目標(biāo)類型與原始類型之間的類型轉(zhuǎn)換無(wú)法完成,dynamic_cast會(huì)返回null指針或拋出std::bad_cast異常。因此,在使用dynamic_cast時(shí)需要非常小心,確保程序的健壯性和安全性。