在C語言中,如果賦值運(yùn)算符左右兩側(cè)類型不同,或者形參與實(shí)參類型不匹配,或者返回值類型與接收返回值類型不一致時,就需要發(fā)生類型轉(zhuǎn)化,C語言中總共有兩種形式的類型轉(zhuǎn)換:隱式類型轉(zhuǎn)換和顯式類型轉(zhuǎn)換。
using namespace std;
void Test ()
{int i = 1;
// 隱式類型轉(zhuǎn)換
double d = i;
printf("%d, %.2f\n" , i, d);
int* p = &i;
// 顯示的強(qiáng)制類型轉(zhuǎn)換
int address =(int)p;
printf("%x, %d\n" , p, address);
}
int main() {Test();
return 0;
}
隱式類型轉(zhuǎn)換:意義相近的類型
char int short float double…整形家族
(它們都是用來表示數(shù)據(jù)大小的,區(qū)別就是存儲的數(shù)據(jù)范圍不同)
強(qiáng)制類型轉(zhuǎn)換:意義不相近
比方說int和指針的意義不想近,所以不可以進(jìn)行隱式類型轉(zhuǎn)換。
但是它們的值轉(zhuǎn)換后有意義。
雖然指針表示一個地址(虛擬地址,都是一個一個的編號),所以可以轉(zhuǎn)。
但如果是一個學(xué)生類的話,我們不能將其轉(zhuǎn)換成整型
隱式類型轉(zhuǎn)換的潛在問題
//在pos位置插入一個字符
void Insert(size_t pos,char ch)
{size_t _size=10;
//我們需要把數(shù)據(jù)向后挪動
size_t end=_size-1;
//即使我們將size_t寫成了int,依舊會進(jìn)入死循環(huán)
//因?yàn)檫@里的符號運(yùn)算也會發(fā)生整形類型提升
//也就是隱式類型提升,讓我們的end變成一個無符號整形
while(end>=pos)
{// _str[end+1]=_str[end];
--end;
}
}
int main() {Insert(5,'a');
//會陷入死循環(huán),因?yàn)槲覀兊膃nd是一個無符號整型,所以根本就不可能為負(fù)數(shù),所以會一直進(jìn)行插入操作。
Insert(0,'a');
return 0;
}
C風(fēng)格的轉(zhuǎn)換格式很簡單,但是有不少缺點(diǎn)的:
標(biāo)準(zhǔn)C++為了加強(qiáng)類型轉(zhuǎn)換的可視性,引入了四種命名的強(qiáng)制類型轉(zhuǎn)換操作符:
static_cast、reinterpret_cast、const_cast、dynamic_cast
static_cast用于非多態(tài)類型的轉(zhuǎn)換(靜態(tài)轉(zhuǎn)換),編譯器隱式執(zhí)行的任何類型轉(zhuǎn)換都可用static_cast,但它不能用于兩個不相關(guān)的類型進(jìn)行轉(zhuǎn)換(用于意義相近的類型:整型,浮點(diǎn))
int main()
{double d = 12.34;
int a = static_cast(d);
cout<
那如果不是相近的類型能不能轉(zhuǎn)換呢?
不可以的!
int main()
{int*p=&a;
int address=static_cast(p);
return 0;
}
2.reinterpret_cast重新詮釋reinterpret_cast操作符通常為操作數(shù)的位模式提供較低層次的重新解釋,用于將一種類型轉(zhuǎn)換為另一種不同的類型
(可以用于不同的數(shù)據(jù)類型進(jìn)行轉(zhuǎn)換)
typedef void (* FUNC)();
int DoSomething (int i)
{cout<<"DoSomething"<//
// reinterpret_cast可以編譯器以FUNC的定義方式去看待DoSomething函數(shù)
// 所以非常的BUG,下面轉(zhuǎn)換函數(shù)指針的代碼是不可移植的,所以不建議這樣用
// C++不保證所有的函數(shù)指針都被一樣的使用,所以這樣用有時會產(chǎn)生不確定的結(jié)果
//
FUNC f = reinterpret_cast< FUNC>(DoSomething );
f();
}
int main()
{Test();
}
3.const_castconst_cast最常用的用途就是刪除變量的const屬性,方便賦值
int main()
{const int a = 2;
int* p = const_cast< int*>(&a );
*p = 3;
cout<
在C++中,這里的常量為常變量,可以修改,但是不能直接進(jìn)行修改,我們可以通過上面的形式進(jìn)行修改。
為什么是2和3,不是3和3
編譯器對于const類型是有優(yōu)化的,因?yàn)榫幾g器認(rèn)為const類型的變量不會被修改,那每次從內(nèi)存中取的話,就會非常慢,那C++就將上面的a直接加載到一個寄存器當(dāng)中,每次訪問的時候(讀取數(shù)據(jù))直接去這個寄存器中讀取數(shù)據(jù)就可以了。雖然你的內(nèi)存中的數(shù)據(jù)被改成3了,但是寄存器中的數(shù)據(jù)并沒有被修改。
為什么const_cast需要單獨(dú)拿出來?
因?yàn)閏onst_cast很危險,所以我們將其單獨(dú)拿出來
int main()
{//告訴編譯器不要優(yōu)化了,每次都去內(nèi)存中取我們的值
volatile const int a = 2;
int* p = const_cast< int*>(&a );
*p = 3;
cout<
int main()
{//告訴編譯器不要優(yōu)化了,每次都去內(nèi)存中取我們的值
volatile const int a = 2;
// int* p = const_cast< int*>(&a );
//C語言的也是可以使用的
int *p=(int*)&a;
*p = 3;
cout<
小總結(jié)1.兼容C隱式類型轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換
2.期望不要用了,期望你通用規(guī)范的C++顯式的強(qiáng)制類型轉(zhuǎn)換
3.static_cast對應(yīng)隱式類型轉(zhuǎn)換
reinterpret_cast、const_cast對應(yīng)的是強(qiáng)制類型轉(zhuǎn)換
dynamic_cast用于將一個父類對象的指針/引用轉(zhuǎn)換為子類對象的指針或引用(動態(tài)轉(zhuǎn)換)
向上轉(zhuǎn)型:子類對象指針/引用->父類指針/引用(不需要轉(zhuǎn)換,賦值兼容規(guī)則)
向下轉(zhuǎn)型:父類對象指針/引用->子類指針/引用(用dynamic_cast轉(zhuǎn)型是安全的)
注意:
子類給父類是向上轉(zhuǎn)換,是C++的一個特例,是賦值兼容的,雖然兩個對象的類型不一樣,但是所有的類型轉(zhuǎn)換都會產(chǎn)生臨時變量
int main()
{int i=0;
//將i轉(zhuǎn)給臨時變量,然后再將這個值給d
double d=i;
//臨時變量具有常性,所以我們不能直接將i賦值給rd
// double& rd=i;
//加上const就可以了
//c語言的寫法
const double& rd1=i;
//C++的寫法
const double& rd2=static_cast(i);
}
class A
{public:
int _a=0;
};
class B:public A{public:
int _b=0;
};
int main()
{B bb;
//進(jìn)行切片,然后轉(zhuǎn)換。
A aa1=bb;
A& ra1=bb;
}
父類是不允許轉(zhuǎn)換成子類的,無論是我們上面說的C++中的四個轉(zhuǎn)換中的任何一個都是不可以的。
指針也引用要允許轉(zhuǎn)換!
為什么指針和引用要允許轉(zhuǎn)換(為什么允許指針或者對象向下轉(zhuǎn)換呢?)
因?yàn)楦割惖闹羔樣锌赡苤赶蚋割悓ο?,也有可能指向子類對象?/p>
如果你是一個父類的指針,你原本只能查看四個字節(jié)的大小,但是你如果現(xiàn)在能查看8個字節(jié)的大小,那么,這就是越界訪問了。
(你的父類的指針指向一個子類的對象,但是你如果訪問到了子類的部分,你就是越界訪問,這是不被允許的)
但是你用dynamic_cast去轉(zhuǎn)換,那么你就是安全的
class A
{public :
virtual void f(){}
int _a;
};
class B : public A
{int _b;
};
//A*的指針有可能指向父類,也有可能指向子類,
void fun (A* pa)
{//如果pa指向子類,那么可以轉(zhuǎn)換,重新轉(zhuǎn)換成子類,這種方式是安全的
//如果pa指向父類,那么不能轉(zhuǎn)換,轉(zhuǎn)換表達(dá)式為nullptr
// dynamic_cast會先檢查是否能轉(zhuǎn)換成功,能成功則轉(zhuǎn)換,不能則返回
B* pb1 = dynamic_cast(pa);
cout<<"pb1:"<A a;
B b;
fun(&a);
fun(&b);
fun(nullptr);
return 0;
}
如果是static_cast或者c語言的轉(zhuǎn)換的話,可以轉(zhuǎn)換,但是其實(shí)已經(jīng)越界訪問了
class A
{public :
virtual void f(){}
int _a;
};
class B : public A
{int _b;
};
//A*的指針有可能指向父類,也有可能指向子類,
void fun (A* pa)
{//如果pa指向子類,那么可以轉(zhuǎn)換,重新轉(zhuǎn)換成子類,這種方式是安全的
//如果pa指向父類,那么不能轉(zhuǎn)換,轉(zhuǎn)換表達(dá)式為nullptr
B* pb1 = static_cast(pa);
B* pb2=(B*)pa;
cout<<"pb1:"<A a;
B b;
fun(&a);
fun(&b);
fun(nullptr);
return 0;
}
在多繼承中的使用情況
class A1
{public :
virtual void f(){}
int _a1;
};
class A2
{public :
virtual void f(){}
int _a2;
};
class B : public A1,public A2
{public:
int _b;
};
int main ()
{B bb;
A1* ptr1=&bb;
A2* ptr2=&bb;
cout<(ptr1);
B* pb6=dynamic_cast(ptr2);
cout<
它會把我們的指針偏移給修改回去。都會重新指向子類對象的起始位置,不會因?yàn)閮蓚€不同的父類的指針指向子類的對象而產(chǎn)生不同。
強(qiáng)制類型轉(zhuǎn)換能夠?qū)⑽覀兊念愋娃D(zhuǎn)換給規(guī)范起來,我們最好去遵守這些規(guī)范。
RAII
初始化一個對象。將資源交給這個對象進(jìn)行管理
(資源獲得即初始化)
RTTI(Run_time Type identification)
運(yùn)行時類型識別
1.typeid運(yùn)算符,拿到對象的類型的字符串,幫助我們觀察
2.dynamic_cast運(yùn)算符,用來識別父類的指針是指向父類的對象還是指向子類的對象、
3.decltype
推導(dǎo)一個對象類型,可以用來定義另一個對象。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
網(wǎng)站欄目:C++【類型轉(zhuǎn)換】-創(chuàng)新互聯(lián)
鏈接URL:http://aaarwkj.com/article4/ccccie.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、Google、軟件開發(fā)、網(wǎng)站建設(shè)、網(wǎng)站改版、動態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容