C 強制型別轉換

2021-09-05 20:13:27 字數 3565 閱讀 3135

c++ 相容 c,對於c語言的型別轉換也是支援的。但是c風格的型別轉換有很多缺點,它可以任意型別之間進行轉換,查詢源型別比較麻煩,而且有的型別之間進行轉換是不安全的行為。c++的設計強調型別安全,為了修補這個大坑,c++提供了四種的型別轉換:static_cast,const_cast,dynamic_cast,reinterpret_cast。各個轉型動作專門用於不同的方面,這樣目標越窄化,編譯器可能診斷出錯誤的運用。

對於c的寫碼形式為:

(type) 	expression
對於c++寫碼形式為:

static_cast( expression )

const_cast( expression )

....

下面就對這四種型別轉換進行整理。

任何具有明確定義的型別轉換,和c的轉換相同,以及相同的限制。比如:不能將乙個struct轉換成int,或將double轉換成指標,也無法移除表示式的常量性(那是const_cast做的事情)。舉幾個例子:

int a = 1;

double b = 3.5;

a = static_cast( b );

b = static_cast( a );

static_cast是適用範圍最廣的轉換,後面的三個適用於更窄的目的。

用來改變表示式中的常量性或易變性。一旦我們對某個物件使用了const_cast,編譯器就不在阻止我們對該物件的寫操作。如:

const char* pc;	

char* p = const_cast( pc ); //可以通過p寫值了

int a = 3;

const int* pint = &a;

int* pint2 = const_cast(pint);

*pint2 = 4;

cout << *pint << " " << *pint2 << endl; //輸出 4 4

如果將const_cast應用於其它用途,那麼轉型動作會被拒絕。同樣的只有const_cast能改變表示式的常量屬性,使用其它c++形式的強制型別轉換會引發編譯器錯誤。

但需要特別注意的是const_cast不是用於去除變數的常量性,而是去除指向常數物件的指標或引用的常量性

const int a = 10;

int b = const_cast(a); //編譯錯誤:

const_cast只能去除頂層const屬性,比如:

const char* const pchar = "abcd";

char* pchar2 = const_cast(pchar);

pchar2 = 'b'; //執行時崩潰,只是去除了頂層const,pchar2相當於char* const pchar2 =.... 不能改變指向

用來執行繼承體系中安全的向下轉型動作。即將基類的指標或引用安全的轉換成派生類的指標或引用

需要注意的是轉換的基類中需要有虛函式。因為通過之前對虛函式的整理,我們知道型別資訊儲存在虛函式表中。

指標型別的dynamic_cast轉換失敗後,會返回空指標。我們判斷返回值來保證**安全。例:

if( derived* pd = dynamic_cast( pb))

引用型別的dynamic_cast因為引用不存在空引用,所以引用型別的轉換失敗後會拋出名為 std::bad_cast 的異常。我們對異常進行捕捉來保證**安全。如:

void f( base& b)

catch ( bad_cast )

}

dynamic_cast是唯一在執行時處理的,要進行型別檢查,所以效率會比較低,盡量少使用。

用來為運算物件的位模式提供較低層次上的重新解釋,不會改變其值。簡單點講有點像對型別的重新解釋,一般用於指標、引用。例:

int* pi;

char* pc = reinterpret_cast( pi );

我們要牢記pc所指的真實型別,否則使用不當,會引發執行時錯誤。例如:

string str( pc );
使用reinterpret_cast強制轉換過程僅僅只是位元位的拷貝,因此在使用過程中需要特別謹慎。有乙個笑話說為啥這個轉換名稱這麼長?因為設計者也不想讓你使用它,所以把它的名字設計的這麼複雜。

許多人相信,轉型其實什麼都沒做,只是告訴編譯器把某種新型別視為另一種型別。但其實是錯誤的。

比如:

int x,y;

...double d = static_cast(x)/y;

將 int x 轉型為 double 幾乎肯定會產生一些**,因為在大部分計算機體系結構中,int的底層表述不同於double底層表述。

還有:

class base;

class derived : public base ;

derived d;

base* pb = &d; //隱喻地將derived* 轉換為 base*

對於派生類的物件,可能擁有乙個以上的位址。之前整理的虛函式及多型原理中講述過這個原理。在多重繼承時,會有多個虛函式表,而轉換為不同的基類時,要對虛指標進行偏移操作。而不同的物件布局方式隨著編譯器的不同而不同,有可能在乙個平台行得通,而在其它平台就行不通

還有一點是dynamic_cast執行的速度是非常慢的。例如至少有乙個很普通的實現版本基於「class名稱之字串比較」,如果你在四層深的單繼承體系內的某個物件上執行 dynamic_cast ,剛才說的那個實現版本可能會耗用四次strcmp呼叫,用以比較class名稱。深度繼承或多重繼承的成本更高。

使用dynamic_cast的情況是,你有乙個指向base的指標或引用,你只能靠它來處理物件,但是你又想呼叫派生類中的函式。最好的辦法就是把處理的函式寫成虛函式,這樣直接使用指向base的指標或引用就可呼叫。

所以可以總結為:

如果可以,盡量避免轉型,特別是注重效率的**中避免dynamic_cast。如果有個設計需要轉型動作,試著發展無須轉型的替代設計

如果轉型是必要的,試著將它隱藏於某個函式背後。客戶隨後可以呼叫該函式,而不需要將轉型放進他們自己的**中

寧可使用c++ 新式轉型,不要使用舊式轉型。前者很容易辨識出來,而且也比較有著分門別類的職能

感謝大家,我是假裝很努力的youngyangd(小羊)

參考資料:

《effective c++》

《c++ primer 第五版》

《more effective c++》

C 強制型別轉換

四種型別可能很多人都常常忽略就象我一樣,但是有時還是比較有用的。不了解的建議看看,一些機制我也不是十分了解,只是將一些用法寫出來讓大家看看。強制轉化無論從語法還是語意上看,都是c 中最難看的特徵之一。但是基於c風格的轉化的語義的不明確性及其一些潛在問題。強制型別轉化最終還是被c 接受了。1.stat...

C 強制型別轉換

標準c 中主要有四種強制轉換型別運算子 const cast,reinterpret cast,static cast,dynamic cast等等。1 static cast a 將位址a轉換成型別t,t和a必須是指標 引用 算術型別或列舉型別。表示式static cast a a的值轉換為模板中...

C 強制型別轉換

關於強制型別轉換的問題,很多書都討論過,寫的最詳細的是c 之父的 c 的設計和演化 最好的解決方法就是不要使用c風格的強制型別轉換,而是使用標準c 的型別轉換符 static cast,dynamic cast。標準c 中有四個型別轉換符 static cast,dynamic cast,reint...