您好,登錄后才能下訂單哦!
小編給大家分享一下C++如何強(qiáng)制類型轉(zhuǎn)換,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
C語言中的強(qiáng)制轉(zhuǎn)換主要用于普通數(shù)據(jù)類型、指針的強(qiáng)制轉(zhuǎn)換,沒有類型檢查,轉(zhuǎn)換不安全,
語法為:
(type-id)expression//轉(zhuǎn)換格式1 type-id(expression)//轉(zhuǎn)換格式2(基本已經(jīng)不用了)
C++除了能使用c語言的強(qiáng)制類型轉(zhuǎn)換外,還新增了四種強(qiáng)制類型轉(zhuǎn)換:static_cast
、dynamic_cast
、const_cast
、reinterpret_cast
,
主要運(yùn)用于繼承關(guān)系類間的強(qiáng)制轉(zhuǎn)化,語法為:
//靜態(tài)轉(zhuǎn)換 static_cast<new_type> (expression) //動(dòng)態(tài)轉(zhuǎn)換 dynamic_cast<new_type> (expression) //常量轉(zhuǎn)換 const_cast<new_type> (expression) //重新解釋轉(zhuǎn)換 reinterpret_cast<new_type> (expression)
其中new type
為轉(zhuǎn)換后的新類型,expression
為舊類型
用法: static_cast <類型說明符> (變量或表達(dá)式)
static_cast
靜態(tài)轉(zhuǎn)換相當(dāng)于C語言中的強(qiáng)制轉(zhuǎn)換,但不能實(shí)現(xiàn)普通指針數(shù)據(jù)(空指針除外)的強(qiáng)制轉(zhuǎn)換,一般用于父類和子類指針、引用間的相互轉(zhuǎn)換。
用于類層次結(jié)構(gòu)中基類(父類)和派生類(子類)之間 指針 或 引用 的轉(zhuǎn)換。不管是否發(fā)生多態(tài),父子之間互轉(zhuǎn)時(shí),編譯器都不會(huì)報(bào)錯(cuò)。
(1)進(jìn)行 上行轉(zhuǎn)換 (把派生類的指針或引用轉(zhuǎn)換成基類表示)是 安全 的;
(2)進(jìn)行 下行轉(zhuǎn)換 (把基類指針或引用轉(zhuǎn)換成派生類表示)時(shí),由于沒有動(dòng)態(tài)類型檢查,所以是 不安全 的,但是編譯器不會(huì)報(bào)錯(cuò)。
用于基本數(shù)據(jù)類型之間的轉(zhuǎn)換,如把int轉(zhuǎn)換成char,把int轉(zhuǎn)換成enum。這種轉(zhuǎn)換的安全性也要開發(fā)人員來保證。
把空指針轉(zhuǎn)換成目標(biāo)類型的空指針。
把任何指針類型轉(zhuǎn)換成空指針類型。
注意:static_cast不能轉(zhuǎn)換掉expression的const、volatile、或者_(dá)_unaligned屬性
如果涉及到類的話,static_cast
只能在有相互聯(lián)系的類型中進(jìn)行相互轉(zhuǎn)換,不一定包含虛函數(shù)。
在C++語言中static_cast
用于數(shù)據(jù)類型的強(qiáng)制轉(zhuǎn)換,強(qiáng)制將一種數(shù)據(jù)類型轉(zhuǎn)換為另一種數(shù)據(jù)類型。例如將整型數(shù)據(jù)轉(zhuǎn)換為浮點(diǎn)型數(shù)據(jù)。
[例1]C語言所采用的類型轉(zhuǎn)換方式:
#include <iostream> using namespace std; int main() { int a = 10; int b = 3; double result = (double)a / (double)b; cout << result << endl; // 3.33333 return 0; }
例1中將整型變量a和b轉(zhuǎn)換為雙精度浮點(diǎn)型,然后相除。在C++語言中,我們可以采用static_cast關(guān)鍵字來進(jìn)行強(qiáng)制類型轉(zhuǎn)換,如下所示。
[例2]static_cast關(guān)鍵字的使用:
#include <iostream> using namespace std; int main() { int a = 10; int b = 3; double result = static_cast<double> (a) / static_cast<double> (b); //其實(shí)寫一個(gè) static_cast<double> 就行 cout << result << endl; // 3.33333 return 0; }
在本例中同樣是將整型變量a轉(zhuǎn)換為雙精度浮點(diǎn)型。采用static_cast
進(jìn)行強(qiáng)制數(shù)據(jù)類型轉(zhuǎn)換時(shí),將想要轉(zhuǎn)換成的數(shù)據(jù)類型放到尖括號(hào)中,將待轉(zhuǎn)換的變量或表達(dá)式放在元括號(hào)中。
在C語言中,const
限定符通常被用來限定變量,用于表示該變量的值不能被修改。
上邊的 static_cast
不能將 const int*
轉(zhuǎn)成 int*
,const_cast
就可以,
用法: const_cast<type-i> (expression)
const_cast
,用于修改類型的const
或volatile
屬性,只能對(duì)是 引用 或者 指針 的變量添加或移除const
。(除了const
或volatile
修飾之外, type_id
和expression
的類型是一樣的。)
const_cast
則正是用于強(qiáng)制去掉這種不能被修改的常數(shù)特性,但需要特別注意的是const_cast
不是用于去除變量的常量性,而是去除 指向常數(shù)對(duì)象的指針或引用 的常量性,其去除常量性的對(duì)象必須為指針或引用。
常量指針被轉(zhuǎn)化成非常量指針,并且仍然指向原來的對(duì)象;
常量引用被轉(zhuǎn)換成非常量引用,并且仍然指向原來的對(duì)象;常量對(duì)象被轉(zhuǎn)換成非常量對(duì)象。
int main() { const int a = 10; const int* p = &a; int* q = const_cast<int*>(p); *q = 20; //fine cout << "a=" << a << " " << "&a = " << &a << endl; cout << "*p=" << *p << " " << "p = " << p << endl; cout << "*q=" << *q << " " << "q = " << q << endl; return 0; } //a = 10 & a = 012FFC10 //* p = 20 p = 012FFC10 //* q = 20 q = 012FFC10 int main() { int c = 11; const int a = c; const int* p = &a; int* q = const_cast<int*>(p); *q = 20; //fine cout << "a=" << a << " " << "&a = " << &a << endl; cout << "*p=" << *p << " " << "p = " << p << endl; cout << "*q=" << *q << " " << "q = " << q << endl; return 0; } //a = 20 &a = 007BFD64 //* p = 20 p = 007BFD64 //* q = 20 q = 007BFD64 int main() { const int c = 11; const int a = c; const int* p = &a; int* q = const_cast<int*>(p); *q = 20; //fine cout << "a=" << a << " " << "&a = " << &a << endl; cout << "*p=" << *p << " " << "p = " << p << endl; cout << "*q=" << *q << " " << "q = " << q << endl; return 0; } //a = 11 & a = 00EFFB44 //* p = 20 p = 00EFFB44 //* q = 20 q = 00EFFB44
查看運(yùn)行結(jié)果,問題來了,指針p和指針q都是指向a變量的,指向地址相同,而且經(jīng)過調(diào)試發(fā)現(xiàn)012FFC10
地址內(nèi)的值確實(shí)由10被修改成了20,這是怎么一回事呢?為什么a的值打印出來還是10呢?
其實(shí)這是一件好事,我們要慶幸a變量最終的值沒有變成20!變量a一開始就被聲明為一個(gè)常量變量,不管后面的程序怎么處理,它就是一個(gè)常量,就是不會(huì)變化的。試想一下如果這個(gè)變量a最終變成了20會(huì)有什么后果呢?對(duì)于這些簡短的程序而言,如果最后a變成了20,我們會(huì)一眼看出是q指針修改了,但是一旦一個(gè)項(xiàng)目工程非常龐大的時(shí)候,在程序某個(gè)地方出現(xiàn)了一個(gè)q這樣的指針,它可以修改常量a,這是一件很可怕的事情的,可以說是一個(gè)程序的漏洞,畢竟將變量a聲明為常量就是不希望修改它,如果后面能修改,這就太恐怖了。
我們稱“*q=20”語句為未定義行為語句,所謂的未定義行為是指在標(biāo)準(zhǔn)的C++規(guī)范中并沒有明確規(guī)定這種語句的具體行為,該語句的具體行為由編譯器來自行決定如何處理。對(duì)于這種未定義行為的語句我們應(yīng)該盡量予以避免!
在C++語言中,reinterpret_cast
主要有三種強(qiáng)制轉(zhuǎn)換用途:
改變指針或引用的類型
將指針或引用轉(zhuǎn)換為一個(gè)足夠長度的整形
將整型轉(zhuǎn)換為指針或引用類型
用法: reinterpret_cast<type_id> (expression)
type-id
必須是一個(gè)指針、引用、算術(shù)類型、函數(shù)指針或者成員指針。
它可以把一個(gè)指針轉(zhuǎn)換成一個(gè)整數(shù),也可以把一個(gè)整數(shù)轉(zhuǎn)換成一個(gè)指針(先把一個(gè)指針轉(zhuǎn)換成一個(gè)整數(shù),在把該整數(shù)轉(zhuǎn)換成原類型的指針,還可以得到原先的指針值)。
我們映射到的類型僅僅是為了故弄玄虛和其他目的,這是所有映射中最危險(xiǎn)的。(這句話是C++編程思想中的原話)。因此, 你需要謹(jǐn)慎使用 reinterpret_cast
。
int *a = new int; double *d = reinterpret_cast<double *>(a);
在上面代碼中,將整型指針通過reinterpret_cast
強(qiáng)制轉(zhuǎn)換成了雙精度浮點(diǎn)型指針。reinterpret_cast
可以將指針或引用轉(zhuǎn)換為一個(gè)足夠長度的整形,此中的足夠長度具體長度需要多少則取決于操作系統(tǒng),如果是32位的操作系統(tǒng),就需要4個(gè)字節(jié)及以上的整型,如果是64位的操作系統(tǒng)則需要8個(gè)字節(jié)及以上的整型。
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(); }
主要用于類層次結(jié)構(gòu)中基類(父類)和派生類(子類)之間指針或引用的轉(zhuǎn)換(只能用于類間轉(zhuǎn)換,支持類間交叉轉(zhuǎn)換,不能操作普通數(shù)據(jù)。)
(1)在類的轉(zhuǎn)換時(shí),在類層次間進(jìn)行上行轉(zhuǎn)換時(shí),dynamic_cast
和static_cast
的效果是一樣的。在進(jìn)行下行轉(zhuǎn)換時(shí),dynamic_cast
具有類型檢查的功能,比static_cast
更安全。
向上轉(zhuǎn)換,即為子類指針指向父類指針(一般不會(huì)出問題);向下轉(zhuǎn)換,即將父類指針轉(zhuǎn)化子類指針。
向下轉(zhuǎn)換的成功與否還與將要轉(zhuǎn)換的類型有關(guān),即要轉(zhuǎn)換的指針指向的對(duì)象的實(shí)際類型與轉(zhuǎn)換以后的對(duì)象類型一定要相同,否則轉(zhuǎn)換失敗。
在C++中,編譯期的類型轉(zhuǎn)換有可能會(huì)在運(yùn)行時(shí)出現(xiàn)錯(cuò)誤,特別是涉及到類對(duì)象的指針或引用操作時(shí),更容易產(chǎn)生錯(cuò)誤。Dynamic_cast
操作符則可以在運(yùn)行期對(duì)可能產(chǎn)生問題的類型轉(zhuǎn)換進(jìn)行測試。
(2)發(fā)生多態(tài)時(shí),允許互相轉(zhuǎn)換。
(3)無繼承關(guān)系的類之間也可以相互轉(zhuǎn)換,類之間的交叉轉(zhuǎn)換。
(4)如果dynamic_cast
語句的轉(zhuǎn)換目標(biāo)是指針類型并且失敗了,則結(jié)果為0。如果轉(zhuǎn)換目標(biāo)是引用類型并且失敗了,則dynamic_cast
運(yùn)算符將拋出一個(gè)std::bad_cast
異常
(5)使用 dynamic_cast
進(jìn)行轉(zhuǎn)換的,基類中一定要有虛函數(shù),否則編譯不通過(類中存在虛函數(shù),就說明它有想要讓基類指針或引用指向派生類對(duì)象的情況,此時(shí)轉(zhuǎn)換才有意義)。這是由于運(yùn)行時(shí)類型檢查需要運(yùn)行時(shí)類型信息,而這個(gè)信息存儲(chǔ)在類的虛函數(shù)表中,只有定義了虛函數(shù)的類才有虛函數(shù)表。
class base { public: void print1() { cout << "in class base" << endl; } }; class derived : public base { public: void print2() { cout << "in class derived" << endl; } }; int main() { derived* p, * q; // p = new base; // Compilr Error: 無法從 "base * " 轉(zhuǎn)換為 "derived * " // Compile Error: Cannot cast from 'base*' to 'derived*' via dynamic_cast: expression type is not polymorphic(多態(tài)的) // p = dynamic_cast<derived *>(new base); q = static_cast<derived*>(new base); // ok, but not recommended(推薦) q->print1(); // in class base q->print2(); // in class derived return 0; }
從上邊的代碼可以看出用一個(gè)派生類的指針是不能直接指向一個(gè)基類的對(duì)象的,會(huì)出現(xiàn)編譯錯(cuò)誤。用 dynamic_cast
的話也會(huì)編譯錯(cuò)誤,提示我們基類不是多態(tài)的,也就是基類中沒有虛函數(shù)??梢钥吹?static_cast
是可以編譯通過的,且輸出結(jié)果看起來都是對(duì)的
static_cast
強(qiáng)制類型轉(zhuǎn)換時(shí)并不具有保證類型安全的功能,而 C++ 提供的 dynamic_cast
卻能解決這一問題,dynamic_cast
可以在程序運(yùn)行時(shí)檢測類型轉(zhuǎn)換是否類型安全。當(dāng)然 dynamic_cast
使用起來也是有條件的,它要求所轉(zhuǎn)換的 expression
必須包含多態(tài)類類型(即至少包含一個(gè)虛函數(shù)的類)。
static_cast:在功能上基本上與C風(fēng)格的類型轉(zhuǎn)換一樣強(qiáng)大,含義也一樣。它有功能上的限制。例如,你不能用static_cast
像用C風(fēng)格轉(zhuǎn)換一樣把struct
轉(zhuǎn)換成int
類型或者把double
類型轉(zhuǎn)換成指針類型。另外,static_cast
不能從表達(dá)式中去除const
屬性,因?yàn)榱硪粋€(gè)新的類型轉(zhuǎn)換符const_cast
有這樣的功能??梢造o態(tài)決議出類型的轉(zhuǎn)換可能性,即使是在繼承體系中,即使包括了多重繼承和虛繼承,只要可以進(jìn)行靜態(tài)決議就可以轉(zhuǎn)換成功
const_cast:用于類型轉(zhuǎn)換掉表達(dá)式的const
或volatile
屬性。通過使用const_cast
,你向人們和編譯器強(qiáng)調(diào)你通過類型轉(zhuǎn)換想做的只是改變一些東西的constness
或者volatieness
屬性。這個(gè)含義被編譯器所約束。如果你試圖使用const_cast
來完成修改constness
或者volatileness
屬性之外的事情,你的類型轉(zhuǎn)換將被拒絕。
reinterpret_cast:使用這個(gè)操作符的類型轉(zhuǎn)換,其轉(zhuǎn)換結(jié)果幾乎都是執(zhí)行期定義。因此,使用reinterpret_cast
的代碼很難移植。reinterpret_casts
的最普通的用途就是在函數(shù)指針類型之間進(jìn)行轉(zhuǎn)換。
dynamic_cast:它被用于安全地沿著類的繼承關(guān)系向下進(jìn)行類型轉(zhuǎn)換。這就是說,你能用dynamic_cast
把指向基類的指針或引用轉(zhuǎn)換成指向其派生類或其兄弟類的指針或引用,而且你能知道轉(zhuǎn)換是否成功。失敗的轉(zhuǎn)換將返回空指針(當(dāng)對(duì)指針進(jìn)行類型轉(zhuǎn)換時(shí))或者拋出異常(當(dāng)對(duì)引用進(jìn)行類型轉(zhuǎn)換時(shí))。
RTTI(Run-time Type identification) :
通過運(yùn)行時(shí)類型信息程序能夠使用 基類的指針或引用 來檢查這些指針或引用所指的對(duì)象的實(shí)際派生類型。(運(yùn)行時(shí)類型識(shí)別)
(1)typeid
操作符,返回指針和引用所指的實(shí)際類型:
可以判斷變量的類型,可以判斷兩個(gè)變量的類型是否相同,可以打印變量的類型(name())
比如:typeid(a).name()
就能知道變量a是什么類型
(2)dynamic_cast
操作符,將基類類型的指針或引用安全地轉(zhuǎn)換為派生類型的指針或引用:
利用RTTI技術(shù)進(jìn)行識(shí)別的父子類指針間轉(zhuǎn)化。會(huì)阻止原生的父類指針轉(zhuǎn)換為子類指針。阻止的方式是扔出一個(gè)bad_cast
異常,且表達(dá)式的值變?yōu)?code>NULL。
以上是“C++如何強(qiáng)制類型轉(zhuǎn)換”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。