您好,登錄后才能下訂單哦!
前言
一說起強制類型轉換大家都很熟悉,相信很多學習完C++的朋友還在使用C語言的強制類型的方式 (類型)變量.
C++其實也具有自己的一套強制類型轉換它們分明是:static_cast reinterpret_cast const_cast dynamic_cast四種類型.
那么肯定會有人好奇C++是不是閑,C語言的強制類型用的舒舒服服的,為什么要新推出來這幾個?
新類型的強制轉換可以提供更好的控制強制轉換過程,允許控制各種不同種類的強制轉換。C++中風格是static_cast<type>。C++風格的強制轉換其他的好處是,它們能更清晰的表明它們要干什么。程序員只要掃一眼這樣的代碼,就能立即知道一個強制轉換的目
的。
static_cast
static_cast用于非多態類型的轉換(靜態轉換),任何標準轉換都可以用它,但它不能用于兩個不相關的類型進行轉換.
何為不相關類型? 比如int 和 double char short就是相關類型. 和int*就是不相關類型.
我們來看一看static_cast的用法. 例如,通過將一個運算對象強制轉換成double類型就能使表達式執行浮點數除法:
double slope = static_cast<double>(j) / i;
當static_cast需要把一個較大的算術類型賦值給較小的類型時,static_cast非常有用。此時,強制類型轉換告訴程序的讀者和編譯器:我們知道并且不在乎潛在的精度損失。一般來說,如果編譯器發現一個的算術類型試圖賦值給較小的類型,就會給出警告信息;但是當我們執行了顯式的類型轉換后,警告信息就會被關閉了。
reinterpret_cast
reinterpret_cast有著和C風格的強制轉換同樣的能力。它可以轉化任何內置的數據類型為其他任何的數據類型,也可以轉化任何指針類型為其他的類型。它甚至可以轉化內置的數據類型為指針,無須考慮類型安全或者常量的情形。不到萬不得已絕對用。
因為reinterpret_cast是一個蠻bug的操作,下面我來演示一下.
typedef void (* FUNC)(); int DoSomething (int i) { cout<<"DoSomething" <<endl; return 0; } void Test () { // reinterpret_cast可以編譯器以FUNC的定義方式去看待 DoSomething函數 // 所以非常的BUG,下面轉換函數指針的代碼是不可移植的,所以不建議這樣用 // C++不保證所有的函數指針都被一樣的使用,所以這樣用有時會產生不確定的結果 FUNC f = reinterpret_cast< FUNC>(DoSomething ); f(); }
當你這樣運行的時候,你會發現通過函數指針沒有傳參數調用這個有參數的函數居然可以調用,這就很尷尬了,所以我告訴你不到萬不得已就不要使用reinterpret_cast
const_cast
對于將常量對象轉化為非常量對象的行為,我們一般稱之為“去掉const性質”。一旦我們去掉了某個對象的const性質,編譯器就不再阻止我們對該對象進行寫操作了。如果對象本身不是一個常量,使用強制類型轉換獲得寫權限是合法的行為。然而如果對象是一個常量,再使用const_cast執行寫操作就會產生未定義的后果。
舉個例子:
#include<iostream> #include<Windows.h> #include<assert.h> using namespace std; int main() { const int a = 2; int *p = const_cast<int*>(&a); *p = 3; cout << a << endl; system("pause"); return 0; }
我們有理由的認為在內存當中a的值被修改為3,但是結果呢? 我們來看一看
這不科學啊?? 我們再打開監視窗口看一下a的值.
我們都知道監視窗口看到的都是從內存當中拿到的,但是為什么內存當中為3,打印出來就是2呢? 我來解釋一下.
C++編譯器具有優化功能,當你定一個const的常量的時候,系統覺得它不會被改變了,于是做一個優化把該常量存到寄存器當中,下次訪問的過程更快速一點. 所以當顯示窗口讀取數據的時候,他會直接去寄存器當中讀取數據.而不是去內存,所以導致我們明明該掉了a的值,卻打印不出來,但是如何解決這個問題呢??
c++有一個關鍵字: volatile 該關鍵字的作用防止編譯器優化,這個時候要輸出a就會老老實實的回內存去查看.
#include<iostream> #include<Windows.h> #include<assert.h> using namespace std; int main() { volatile const int a = 2; int *p = const_cast<int*>(&a); *p = 3; cout << a << endl; system("pause"); return 0; }
dynamic_cast
前三種的強制類型轉換,他們能做到的C語言的強制類型轉換也大多能做到,最后一種C語言的強制類型轉換就沒有辦法了.
在類的轉換時,在類層次間進行上行轉換時,dynamic_cast和static_cast的效果是一樣的。在進行下行轉換時,dynamic_cast具有類型檢查的功能,比static_cast更安全。當用于多態類型時,它允許任意的隱式類型轉換以及相反過程. 不過,與static_cast不同,在后一種情況里(注:即隱式轉換的相反過程),dynamic_cast 會檢查操作是否有效. 也就是說, 它會檢查轉換是否會返回一個被請求的有效的完整對象。檢測在運行時進行. 如果被轉換的指針不是一個被請求的有效完整的對象指針,返回值為NULL. 對于引用 類型,會拋出bad_cast異常
你說這個強轉有啥用,其實對于我這種菜鳥還真的沒用過,不過我知道一個問題可以使用這樣的方法解決. 給你兩個類讓你分辨那個是子類那個是父類,我們來看看是如何解決的.
#include<iostream> #include<Windows.h> #include<assert.h> using namespace std; class AA { public: virtual void fun1() { cout << "hehe" << endl; } public: int a; }; class BB :public AA { public: virtual void fun1() { cout << "heh3e" << endl; } public: int c; }; int main() { AA* q = new AA(); BB* p = new BB(); AA* a; BB* b; b = dynamic_cast<BB*>(q); if (b == NULL) { cout << "AA為基類" << endl; } else{ cout << "AA為子類" << endl; } a = dynamic_cast<AA*>(p); if (a == NULL) { cout << "BB為基類" << endl; } else { cout << "BB為子類" << endl; } system("pause"); return 0; }
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。