舊式的類型轉換中有倆種(Effect C++)
//C風格 (T)expression
(int)a//比如這樣子 //函數風格 T(expression)
doSomeWork(Widget(15)) 這里15作為一個參數給類Widget,會以轉型動作創建一個Widget
而C++提供了四種新式轉換。
(1)const_cast:通常用來把對象的常量性一處掉,是唯一有此能力的C++ style轉型操作符。
(2)dynamic_cast:用來指向安全向下轉型
是這樣的,比如有一個base類,有很多派生類,在這個繼承體系里,可以用來決定對象是否歸屬於繼承體系中的某個類型(向下的,也就是從基類指針轉變到某個派生類指針)
這是唯一一個無法通過舊式語法執行的動作,是唯一可能耗費重大運行成本的轉型動作。
成本非常高昂。
(3)static_cast:用來強迫隱式轉換。
比如把non-const對象轉換為const對象(反過來不行,只有const_cast能做到),或者把int轉為double等,還可以把void*指針轉為typed指針,把pointer-to-base轉為pointer-to-derived。
(4)reinterpret_cast:意圖執行低級轉型,效果取決於編譯器。
用於進行各種不同類型的指針之間、不同類型的引用之間以及指針和能容納指針的整數類型之間的轉換。
這個類型轉換會重新去解釋內存中存放的數據的類型,比如說我們強行把一個指向int型的指針(在內存中就是一個整數,只不過是用來解釋為地址的),去解釋為一個int,它可以滿足各種類型的轉換,但是對結果不做保證。
#include <iostream> using namespace std; int main() { int a = 1; int* p1 = &a; char* p2 = reinterpret_cast<char*>(p1); double* p3 = reinterpret_cast<double*>(p1); cout << a << " " << *p2 << " " << *p3 << endl; }
不管是p1,p2,還是p3,指向的都是同一個地址0x0116FA10,里面存放的是a的值,1。
,其他都是一樣的。
輸出結果確是按各自指針類型來解釋的。
轉型實際上是會產生一些代碼的,比如說int和double在內存里表示形式不同,如果我們把int數轉型為double,那在內存中存儲的數據肯定是會改變的,是做了改變的。
//還有一個有趣的事情,
//基類 class Window{ public: virtual void onRize(){...} ... } //派生類 class SpecialWindow:public Window{ public: virtual void onResize() { //轉型,試圖調用Window的onRize(); //這是行不通的! static_cast<Window>(*this).onResize(); } ...//secialWindows專屬行為 }
這一段程序希望吧*this轉型為Window,然后調用Window::onResize。但是實際上,它調用的並不是當前對象上的函數,而是稍早轉型動作所建立的一個"*this對象之base class成分”的暫時副本身上的onResize
函數就是函數,成員函數只有一份,“調用哪個對象身上的函數”有什么關系呢,關鍵在於成員函數身上都有一個(非靜態的)*this指針,會影響到成員函數操作的數據。
所以實際上!他不是在當前對象身上,調用Window::onResize之后,再執行SecialWindow專屬動作,他調用的是哪個臨時副本,。如果Window::onResize修改了對象的內容,當前的對象其實沒有改動,改動的是副本。而SecialWindow::如果改動對象,就真的會改動。
為了避免這種情況,最好這樣寫
virtual void onResize() { Window::onResize();//調用Window::onResize作用於*this的指針上 }
//-----之后也許需要補充一些dynamic_cast相關的問題。參見cherno的dynamic_cast相關視頻