C++實(shí)例講解四種類(lèi)型轉(zhuǎn)換的使用
C++類(lèi)型轉(zhuǎn)換
C語(yǔ)言風(fēng)格的轉(zhuǎn)換
C語(yǔ)言提供了自己的一套轉(zhuǎn)換規(guī)則,有好處也有壞處。
C語(yǔ)言的風(fēng)格:(type_name)expression;
C語(yǔ)言提供了隱式類(lèi)型轉(zhuǎn)換和顯式類(lèi)型轉(zhuǎn)換。顯式類(lèi)型轉(zhuǎn)換一般也叫做強(qiáng)轉(zhuǎn),隱式類(lèi)型轉(zhuǎn)換編譯器完成,如果轉(zhuǎn)換不了就報(bào)錯(cuò)。
而C語(yǔ)言類(lèi)型轉(zhuǎn)換的風(fēng)格好處就是簡(jiǎn)單,缺陷比如轉(zhuǎn)換的可視性差,顯式類(lèi)型轉(zhuǎn)換的寫(xiě)法就只有一種,難以精準(zhǔn)的跟蹤錯(cuò)誤。
??char ch=1.1,char ch=1在.cpp下都是合法的,這就是隱式類(lèi)型轉(zhuǎn)換,C語(yǔ)言下如果把一個(gè)結(jié)構(gòu)體給int就會(huì)報(bào)錯(cuò),因?yàn)榫幾g器不知道怎么去轉(zhuǎn),C++下可以通過(guò)實(shí)現(xiàn)operator int()實(shí)現(xiàn)類(lèi)型轉(zhuǎn)換或者提供合適的構(gòu)造函數(shù)完成隱式類(lèi)型轉(zhuǎn)換,下面以在.cpp中實(shí)現(xiàn)operator int()為例

下面這段代碼由于隱式類(lèi)型轉(zhuǎn)換導(dǎo)致了死循環(huán)

C語(yǔ)言的類(lèi)型轉(zhuǎn)換其實(shí)已經(jīng)足夠完成需求了,但是可視性不太好,比如你不能在代碼庫(kù)中搜索它(就一對(duì)括號(hào)怎么去搜索),所以C++提供了一套類(lèi)型轉(zhuǎn)換,相當(dāng)于語(yǔ)法糖了,此外還會(huì)進(jìn)行一些編譯性檢查(比如dynamic_cast轉(zhuǎn)換失敗則返回空指針)。但其實(shí)作用都是一樣的。
C++風(fēng)格的類(lèi)型轉(zhuǎn)換
C++標(biāo)準(zhǔn)為了增加類(lèi)型轉(zhuǎn)換的可見(jiàn)性,提供了四種類(lèi)型轉(zhuǎn)化的方式。
static_cast
靜態(tài)類(lèi)型轉(zhuǎn)換,進(jìn)行相關(guān)類(lèi)型的轉(zhuǎn)換,但不能轉(zhuǎn)換兩個(gè)不相關(guān)的類(lèi)型(即編譯器看到這個(gè)轉(zhuǎn)換是行不通的就會(huì)報(bào)錯(cuò))。
static_cast < type-id > ( expression )
int main()
{
double a = (int)5.5 + 5.3;//結(jié)果是10.3
double b = static_cast <int>(5.5) + 5.3;
cout << "a: " << a << endl;
cout << "b: " << b << endl;
return 0;
}
轉(zhuǎn)換不相關(guān)的類(lèi)型:

reinterpret_cast
很暴力的一個(gè)操作符,由英文直譯過(guò)來(lái)就是重新解釋的轉(zhuǎn)型。白話就是將一段內(nèi)存重新解釋。
網(wǎng)上看到很多大佬的理解,這里借用或摻雜自己的思想:static_cast是做類(lèi)型能做的轉(zhuǎn)換,不行編譯器就報(bào)錯(cuò),告訴你這樣是不合理的,reinterpret_cast則是就算不能轉(zhuǎn)換編譯器你也別報(bào)錯(cuò),我心里有數(shù)。由于reinterpret_cast本質(zhì)上是一個(gè)編譯器指令,所以實(shí)際動(dòng)作完全取決于編譯器,失去了移植性。
暴力歸暴力,但也是合理范圍內(nèi)的,比如你把一個(gè)結(jié)構(gòu)體硬塞給int肯定是不行的,但是把結(jié)構(gòu)體指針重新解釋為int那是一點(diǎn)問(wèn)題沒(méi)有。
此外reinterpret_cast重新解釋的辦法是把那一塊內(nèi)存的比特位全部復(fù)制下來(lái)重新解釋。
下面的例子把一個(gè)結(jié)構(gòu)體指針解釋為int再加上5.3。
struct Test
{
int a;
};
int main()
{
Test* t = new Test;
double c = reinterpret_cast <int>(&t) + 5.3;
cout << c << endl;
return 0;
}

const_cast
刪除變量的const屬性,一般和指針或引用連用
int main()
{
const int a = 1;//a是常變量,在棧上
int* p = const_cast<int*>(&a);
*p = 2;
cout << a << endl;
cout << *p << endl;
return 0;
}

volatile const int a=1;//打印的a就會(huì)是2
volatile后編譯器對(duì)訪問(wèn)該變量的代碼不再優(yōu)化。比如上面那句代碼打印1就是因?yàn)榫幾g器優(yōu)化,讀取的a是從寄存器中讀取的,而不是內(nèi)存。
多線程中也有很多關(guān)于 volatile的應(yīng)用。
dynamic_cast
dynamic_cast,安全的向下轉(zhuǎn)型。
多態(tài)的轉(zhuǎn)換中向下轉(zhuǎn)型(父類(lèi)轉(zhuǎn)為子類(lèi))用dynamic是安全的,但是父類(lèi)必須有虛函數(shù),否則編譯報(bào)錯(cuò),且只能用于指針或引用。
向上轉(zhuǎn)型,子類(lèi)給父類(lèi),發(fā)生切割,不需要轉(zhuǎn)換。
向下轉(zhuǎn)型,父類(lèi)地址給子類(lèi)指針,需要類(lèi)型轉(zhuǎn)換,由于是類(lèi)型是子類(lèi)指針,但是給的地址是父類(lèi)的,如果用指針去訪問(wèn)子類(lèi)獨(dú)有的數(shù)據(jù)可能就會(huì)造成越界,然后程序就可能崩了,所以此時(shí)就需要dynamic_cast進(jìn)行轉(zhuǎn)換了,因?yàn)閐ynamic_cast會(huì)檢查父類(lèi)指針是否指向的是這個(gè)子類(lèi),如果是父類(lèi)說(shuō)明可能帶來(lái)一些安全問(wèn)題,會(huì)轉(zhuǎn)換失敗返回空指針,反之則實(shí)現(xiàn)轉(zhuǎn)換。
理解向下轉(zhuǎn)型不安全有個(gè)例子:男人是人,但人不一定是男人(男人派生自人,男人的指針=(男人類(lèi)型的指針強(qiáng)轉(zhuǎn))人的地址,此時(shí)如果通過(guò)男人指針去調(diào)用男人自己獨(dú)有的特性就是越界,因?yàn)閷?shí)際上拿到的是人的地址,并沒(méi)有存儲(chǔ)男人的特性,也可以從空間大小上來(lái)解釋?zhuān)耸歉割?lèi),空間更小,男人是子類(lèi),空間更大,給的是小空間,卻有了訪問(wèn)大空間的能力,所以可能造成越界,所以是不安全的)

此外在一個(gè)父類(lèi)有多個(gè)子類(lèi)且需要類(lèi)型轉(zhuǎn)換時(shí),dynamic_cast也能起到作用,舉個(gè)例子
//父類(lèi)是Entity,子類(lèi)是Player和Enemy, e,player,enemy分別表示他們對(duì)應(yīng)的實(shí)例化對(duì)象 Entity* p=&player; Enemy* p1=(Enemy*)p;//向下轉(zhuǎn)型需要強(qiáng)轉(zhuǎn),這樣搞就出問(wèn)題了,p明明指向的是一個(gè)player,現(xiàn)在類(lèi)型為Enemy的指針居然指向了一個(gè)Player的對(duì)象,如果對(duì)其內(nèi)存進(jìn)行了操作,那后果是不可預(yù)料的。
父類(lèi)指針一開(kāi)始指向一個(gè)父類(lèi)對(duì)象,再給到子類(lèi)類(lèi)型的指針,存在越界的風(fēng)險(xiǎn),如果為了保證安全則需要檢查。
父類(lèi)的指針指向子類(lèi)對(duì)象(向上轉(zhuǎn)型),再給到子類(lèi)指針,合理。
所以建議使用dynamic_cast,因?yàn)榭梢员WC安全, 轉(zhuǎn)換失敗返回空指針(NULL)。
dynamic_cast的底層與RTTI有關(guān),借助RTTI拿到類(lèi)型信息,所以dynamic_cast更像一個(gè)函數(shù),因?yàn)椴皇蔷幾g指令,所以會(huì)帶來(lái)一些性能的損失。
RTTI 是“Runtime Type Information”的縮寫(xiě),意思是運(yùn)行時(shí)類(lèi)型信息。RTTI存儲(chǔ)了所有類(lèi)型運(yùn)行時(shí)的類(lèi)型信息,增加了開(kāi)銷(xiāo)但是可以讓我們做更多的操作。dynamic_cast的底層就是借助了RTTI+匹配,具體的不太了解。VS可以關(guān)閉RTTI,但是也就不能用dynamic_cast了
下面給一個(gè)代碼例子
class Entity
{
public:
virtual void Print() {};//dynamic_cast使用的前提必須是父類(lèi)有虛函數(shù)
};
class Player:public Entity
{
};
class Enemy :public Entity
{
};
void Check(void* p)
{
if (p)
{
cout << "轉(zhuǎn)換成功" << endl;
}
else
{
cout << "轉(zhuǎn)換失敗" << endl;
}
}
int main()
{
Entity* e = new Entity();
Entity* actuallyPlayer = new Player();//向上轉(zhuǎn)型
//安全的向下轉(zhuǎn)型
Player* player =(Player*)actuallyPlayer;//向下轉(zhuǎn)型需要轉(zhuǎn)換類(lèi)型
Player* player2 = dynamic_cast<Player*>(actuallyPlayer);
Check(player2); cout << endl;
//不安全的向下轉(zhuǎn)型
Player* player3 = (Player*)e;
Player* player4 = dynamic_cast<Player*>(e);
Check(player4); cout << endl;
Entity* actuallyEnemy = new Enemy();
Player* player5 = dynamic_cast<Player*>(actuallyEnemy);
Check(player5); cout << endl;
return 0;
}
dynamic也常常利用返回值是否是空指針來(lái)判斷指針具體指向誰(shuí)。
用dynamic_cast的地方其實(shí)也可以用static_cast,不過(guò)static_cast不會(huì)進(jìn)行安全檢查,如果你很清楚其指向,并且在安全的前提下,為了減少程序開(kāi)銷(xiāo)那可以考慮用static_cast
小結(jié)
- static_cast用于相關(guān)類(lèi)型的轉(zhuǎn)換
- reinterpret_cast用于重新解釋內(nèi)存(很暴力,用的時(shí)候心里要有數(shù))
- const_cast常用來(lái)取出const屬性,常與指針連用來(lái)修改const變量的值
- dynamic_cast,在多態(tài)里提供安全的向下轉(zhuǎn)換(轉(zhuǎn)換不安全就返回空指針,只要對(duì)返回的指針進(jìn)行判斷我們就能知道此次轉(zhuǎn)換安不安全了)
到此這篇關(guān)于C++實(shí)例講解四種類(lèi)型轉(zhuǎn)換的使用的文章就介紹到這了,更多相關(guān)C++類(lèi)型轉(zhuǎn)換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
使用設(shè)計(jì)模式中的單例模式來(lái)實(shí)現(xiàn)C++的boost庫(kù)
這篇文章主要介紹了使用設(shè)計(jì)模式中的單例模式來(lái)實(shí)現(xiàn)C++的boost庫(kù)的方法,其中作者對(duì)線程安全格外強(qiáng)調(diào),需要的朋友可以參考下2016-03-03
C++關(guān)鍵字mutable學(xué)習(xí)筆記
這篇文章主要為大家介紹了C++關(guān)鍵字mutable學(xué)習(xí)筆記,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
C語(yǔ)言中pthread_exit和pehread_join的使用
pthread_exit用于強(qiáng)制退出一個(gè)線程,pthread_join用于阻塞等待線程退出,獲取線程退出狀態(tài),本文主要介紹了C語(yǔ)言中pthread_exit和pehread_join函數(shù)的使用,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02
C++實(shí)現(xiàn)std::set的示例項(xiàng)目
std::set是C++標(biāo)準(zhǔn)庫(kù)中的關(guān)聯(lián)容器,提供有序唯一元素集合,本文就來(lái)介紹一下std::set的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下2025-02-02
C++實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的事件(Event)的示例代碼
之前在?windows系統(tǒng)中開(kāi)發(fā)應(yīng)用時(shí),?遇到需要進(jìn)行線程同步的時(shí)候幾乎都是使用的事件內(nèi)核對(duì)象?Event。本文為大家整理了C++實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的事件(Event)的相關(guān)資料,需要的可以參考一下2022-11-11
概述C++中的 public protected private friend關(guān)鍵字的用法
這篇文章簡(jiǎn)要概述了C++中的 public protected private friend關(guān)鍵字的用法,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起學(xué)習(xí)吧2016-08-08

