C++是一門弱類型的語言,提供了許多複雜和靈巧類型轉換的方式。筆者以前寫的Python與Go都是強類型的語言,對這種弱類型的設計實在是接受無力啊~~ ( 生活所迫,工做還得寫C++啊~~)C++語言提供了四種類型轉換的操做:static_cast,dynamic_cast,reinterpret_cast,const_cast,今天就來聊一聊,在C++之中應該如何來使用這些類型轉換的。編程
開門見山,先聊聊筆者對類型轉換的見解吧。從設計上看,一門面向對象的語言是不同提供類型轉換的,這種方式破壞了類型系統。C++爲了兼容C也不得不吞下這個苦果,在實際進行編程工做的過程之中,並不太推薦你們使用類型轉換。(Java在這裏就作了一些妥協,在基本類型之中提供了類型轉換。對於對象類型則不提供類型轉換這種黑魔法)安全
C++之中提供了兩種類型轉換的方式,第一種方式沿用了C語言之中的類型轉換,稱之爲舊式類型轉換。提及來也很簡單,舉個栗子:函數
char x = 'c'; int y = (int) x;
這是最簡單的一箇舊式類型轉換,一個char類型被裝換爲一個int類型。可是這種舊式的類型轉換是存在問題的:過於粗暴且極易失控,因此C++新提供了四種新式的類型轉換來替代舊式的類型轉換,這四種類型轉換分別用於不用的轉換場景,接下來筆者來一一梳理一下它們的用法。ui
C++語言提供了四種新式類型轉換的操做:
static_cast,dynamic_cast,reinterpret_cast,const_cast,這些操做都依託了C++的模板來使用,標準的用法是設計
xxx_cast<轉換類型>(轉換參數)
這種新式轉換優於舊式的轉換就在於:編譯器能夠在轉換期間進行更多的檢查,對於一些不符合轉換邏輯的轉換進行一些糾錯。而某些類型轉換操做能夠利用RTTI(運行時類型信息)來確保類型轉換的合理,這是舊式的類型轉換沒法達成的效果。指針
從名字上就能夠看出來,這廝是用來對const屬性進行類型轉換的。這個名字取得有些偏頗,它一樣適用於volatile屬性。它能夠爲變量添加或接觸上述屬性,它也是新式轉換之中惟一具備這個能力的轉換方式,沒有什麼額外的坑,用戶體驗良好:(可是偶爾對於const屬性的轉換須要執行多步,先經過const_cast轉換,再借助其餘轉換)code
//函數須要傳遞const屬性的變量,如atoi atoi(const_cast<const char*>(char_ptr))
static_cast 是靜態的轉換形式,不經過運行時類型檢查來保證轉換的安全性。它主要用於以下場合:對象
用於基本數據類型之間的轉換,如把long轉換成char,把int轉換成char。繼承
void 的空指針轉換成其餘類型的的空指針。資源
上面的幾種概念的比較好理解,這裏筆者着重聊聊上下行轉換:不囉嗦,看代碼:
class Bird { public: virtual void fly() { cout << "I can fly." << endl; } }; class Penguin:public Bird { public: void fly() { cout << "I can't fly." << endl; } };
上述代碼咱們定義了兩個類Bird與Penguin:
int main() { Penguin* p = new (std::nothrow) Penguin; Bird* b = static_cast<Bird *>(p); b->fly(); return 0; }
上行轉換,將派生類轉換爲基類的指針,合法。
int main() { Bird* b = new (std::nothrow) Bird; Penguin* p = static_cast<Penguin *>(b); if (p != nullptr) { p->fly(); } else { } return 0; }
下行轉換,將基類轉換爲派生類的指針,此時程序的行爲是不肯定的。而且編譯期間並無警告,這是一種十分危險的用法,因此使用時必定要謹小慎微。因此接下來就要請出下一種轉換dynamic_cast,這是在對象基類和派生類之間轉換推薦的一種方式。
dynamic_cast主要用於在類層次間進行上下行轉換時,它與static_cast的最大的區別就在於dynamic_cast可以在運行時進行類型檢查的功能,因此作起類型轉換比static_cast更安全,可是dynamic_cast會耗費更多的系統資源。dynamic_cast是沒法經過舊式類型轉換完成的類型轉換。
int main() { Bird* b = new (std::nothrow) Bird; Penguin* p = dynamic_cast<Penguin *>(b); if (p != nullptr) { p->fly(); } else { cout << "cast failed" << endl; } return 0; }
dynamic_cast對於非法的下行轉換會返回空指針,因此能夠在必定程度上避免不安全的類型轉換。
int main() { Bird* b = new (std::nothrow) Bird; Penguin* p = reinterpret_cast<Penguin *>(b); if (p != nullptr) { p->fly(); } else { cout << "cast failed" << endl; } return 0; }
上述代碼依舊能夠轉換成功,結果不可控。
梳理完C++新引進的四種類型轉換符以後,想必你們在實踐之中能夠很好的運用好這些C++的類型轉換。後續筆者還會繼續深刻的探討有關C++之中類型系統相關的內容,歡迎你們多多指教。