本章主要復(fù)習(xí)的是 類(lèi)型之間的互相轉(zhuǎn)換,類(lèi)型好端端的為什么就要轉(zhuǎn)換呢?因?yàn)橄?C++ 語(yǔ)言是強(qiáng)類(lèi)型的語(yǔ)言,所以在賦值或者運(yùn)算的時(shí)候類(lèi)型需要轉(zhuǎn)換一致
那么在C語(yǔ)言中存在著隱式轉(zhuǎn)換和顯示轉(zhuǎn)換著兩種
// 隱式類(lèi)型轉(zhuǎn)換
int i = 1;
double d = i;
// 顯示的強(qiáng)制類(lèi)型轉(zhuǎn)換
int* p = &i;
int address = (int)p;
printf("%x, %d\n", p, address);
缺陷: 轉(zhuǎn)換的可視性比較差,你容易忽視它的轉(zhuǎn)換,所有的轉(zhuǎn)換形式都是以一種相同的形式書(shū)寫(xiě),難以跟蹤錯(cuò)誤
所以引出了 C++強(qiáng)制類(lèi)型轉(zhuǎn)換
標(biāo)準(zhǔn)C++為了 加強(qiáng)類(lèi)型轉(zhuǎn)換的可視性 讓你明確的知道,原來(lái)這個(gè)變量,這個(gè)類(lèi)型已經(jīng)轉(zhuǎn)換為另一種類(lèi)型了,就引入了四種命名的強(qiáng)制類(lèi)型轉(zhuǎn)換操作符:static_cast、reinterpret_cast、const_cast、dynamic_cast
當(dāng)然這篇重要掌握的就是他們之間的區(qū)別?
static_cast 可以實(shí)現(xiàn) C++內(nèi)置基本類(lèi)型的轉(zhuǎn)換;
double d = 12.34;
int a = static_cast<int>(d); // a = 12
它也可以實(shí)現(xiàn)具有繼承關(guān)系類(lèi)型之間的轉(zhuǎn)換
class Base{};
class Derived :public Base{};
Derived d;
Base e = staic_cast<Base>(d);
我們可以看出它是從派生類(lèi)對(duì)象轉(zhuǎn)換為基類(lèi)對(duì)象,那么反過(guò)來(lái)可以嗎?可以把基類(lèi)對(duì)象轉(zhuǎn)換為派生類(lèi)對(duì)象嗎?
不可以,編譯器不允許我們這樣做,因?yàn)闀?huì)不安全!
試想如果把基類(lèi)轉(zhuǎn)換為派生類(lèi)型的話,因?yàn)榕缮?lèi)可能會(huì)派生出基類(lèi)沒(méi)有的東西,所以如果讓轉(zhuǎn)換的那個(gè)對(duì)象去訪問(wèn)派生類(lèi)成員,這個(gè)成員在基類(lèi)可能不存在,這樣就會(huì)引發(fā)錯(cuò)誤!
dynamic_cast 和 static_cast 是相對(duì)的,static_cast 是在編譯的時(shí)候進(jìn)行轉(zhuǎn)換的。它是動(dòng)態(tài)的在運(yùn)行時(shí)候轉(zhuǎn)換的,而且 只能在繼承類(lèi)對(duì)象的指針或引用之間進(jìn)行轉(zhuǎn)換,在進(jìn)行轉(zhuǎn)換的時(shí)候,會(huì)根據(jù)當(dāng)前RTTI (運(yùn)行時(shí)類(lèi)型識(shí)別)判斷類(lèi)型對(duì)象之間的轉(zhuǎn)換是否合法,如果合法就轉(zhuǎn)換成功了,返回了指向類(lèi)的引用或指責(zé),但是如果轉(zhuǎn)換是非法的,則返回NULL或者0
使用 dynamic_cast 進(jìn)行轉(zhuǎn)換的時(shí)候,基類(lèi)一定要有虛函數(shù),另外它向上轉(zhuǎn)換的時(shí)候是兼容的,向下轉(zhuǎn)換的時(shí)候有類(lèi)型安全檢查,比static_cast 要安全
class A {
public:
virtual void f() {}
};
class B : public A
{};
void fun(A* pa) {
// dynamic_cast會(huì)先檢查是否能轉(zhuǎn)換成功,
// 能成功則轉(zhuǎn)換,不能則返回0
cout << "pa" <<' '<< typeid(pa).name()<<pa << endl;
B* pb1 = static_cast<B*>(pa);
B* pb2 = dynamic_cast<B*>(pa);
//pa class A* 00AFFE00
//pb1 class B* 00AFFE00
//pb2 class B* 00000000
//pa class A* 00AFFDF4
//pb1 class B* 00AFFDF4
//pb2 class B* 00AFFDF4
cout << "pb1" <<' '<<typeid(pb1).name()<<' '<< pb1 << endl;
cout << "pb2" <<' '<<typeid(pb2).name()<<' '<< pb2 << endl;
}
int main() {
A a;
B b;
fun(&a);
fun(&b);
system("pause");
return 0;
}
reinterpret_cast 類(lèi)型轉(zhuǎn)換函數(shù) 將一個(gè)類(lèi)型的指針轉(zhuǎn)換為另一個(gè)類(lèi)型的指針。reinterpret 單詞的漢語(yǔ)意思是重新解釋?zhuān)赃@種轉(zhuǎn)換不需要修改指針變量值數(shù)據(jù)存放格式,只需在編譯時(shí)重新編譯解釋指針的類(lèi)型即可
就像這樣
double d = 9.3;
double *pd = &d;
int *pi = reinterpret_cast<int*>(pd);
上面是將 double * 轉(zhuǎn)換為 int * ,但是不可以用于非指針類(lèi)型的轉(zhuǎn)換,reinterpret_cast 同時(shí)也不能將一個(gè)const指針轉(zhuǎn)換為void*指針
reinterpret_cast 這里是將一個(gè)整形函數(shù)轉(zhuǎn)換為函數(shù)指針的類(lèi)型去調(diào)用,但是存在著缺陷(了解)
typedef void(*FUNC)();
int DoSomething(int i){
cout << "DoSomething" << endl;
return 0;
}
void Test(){
// reinterpret_cast可以編譯
// 以FUNC的定義方式去看待DoSomething函數(shù)
// 所以非常的BUG,下面轉(zhuǎn)換函數(shù)指針的代碼是不可移植的,
// 所以不建議這樣用
// C++不保證所有的函數(shù)指針都被一樣的使用,
// 所以這樣用有時(shí)會(huì)產(chǎn)生不確定的結(jié)果
FUNC f = reinterpret_cast<FUNC>(DoSomething);
f();
}
const_cast 最常用的用途就是刪除變量的const屬性,方便賦值
const int* pci = 0;
int* pj = const_cast<int*>(pci);
1
2
經(jīng)過(guò)轉(zhuǎn)換后的 pci 賦值給pj ,不在具備常量的屬性,可以被修改
本站文章版權(quán)歸原作者及原出處所有 。內(nèi)容為作者個(gè)人觀點(diǎn), 并不代表本站贊同其觀點(diǎn)和對(duì)其真實(shí)性負(fù)責(zé),本站只提供參考并不構(gòu)成任何投資及應(yīng)用建議。本站是一個(gè)個(gè)人學(xué)習(xí)交流的平臺(tái),網(wǎng)站上部分文章為轉(zhuǎn)載,并不用于任何商業(yè)目的,我們已經(jīng)盡可能的對(duì)作者和來(lái)源進(jìn)行了通告,但是能力有限或疏忽,造成漏登,請(qǐng)及時(shí)聯(lián)系我們,我們將根據(jù)著作權(quán)人的要求,立即更正或者刪除有關(guān)內(nèi)容。本站擁有對(duì)此聲明的最終解釋權(quán)。