程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 條款2:最好使用C++轉型操作符(1)

條款2:最好使用C++轉型操作符(1)

編輯:C++入門知識

想想低階轉型動作。它幾乎像goto一樣被視為程序設計上的"賤民"。盡管如此,它卻仍能夠苟延殘喘,因為當某種情況愈來愈糟,轉型可能是必要的。是的,當某種情況愈來愈糟,轉型是必要的!

不過,舊式的C轉型方式並非是唯一選擇。它幾乎允許你將任何類型轉換為任何其他類型,這是十分拙劣的。如果每次轉型都能夠更精確地指明意圖,則更好。舉個例子,將一個 pointer-to-const-object 轉型為一個 pointer-to-non-const-object(也就是說只改變對象的常量性),和將一個 pointer-to-base-class-object 轉型為一個pointer-to-derived-class-object(也就是完全改變了一個對象的類型),其間有很大的差異。傳統的 C 轉型動作對此並無區分(這應該不會造成你的驚訝,因為 C 式轉型是為 C 設計的,不是為了 C++)。

舊式轉型的第二個問題是它們難以辨識。舊式轉型的語法結構是由一對小括號加上一個對象名稱(標識符)組成,而小括號和對象名稱在 C++ 的任何地方都有可能被使用。因此,我們簡直無法回答最基本的轉型相關問題"這個程序中有使用任何轉型動作嗎?"。因為人們很可能對轉型動作視而不見,而諸如 grep 之類的工具又無法區分語法上極類似的一些非轉型寫法。

為解決C 舊式轉型的缺點,C++ 導入4個新的轉型操作符(cast operators):static_cast,const_cast,dynamic_cast 和reinterpret_cast。對大部分使用目的而言,面對這些操作符你唯一需要知道的便是,過去習慣的寫碼形式:

  1. (type) expression

現在應該改為這樣:

  1. static_cast(expression)

舉個例子,假設你想要將一個 int 轉型為一個double,以強迫一個整數表達式導出一個浮點數值來。采用 C 舊式轉型,可以這麼做:

  1. int firstNumber, secondNumber; ...
  2. double result = ((double)firstNumber)/secondNumber;

如果采用新的 C++ 轉型法,應該這麼寫:

  1. double result = static_cast(firstNumber)/secondNumber;

這種形式十分容易被辨識出來,不論是對人類或是對工具程序而言。

static_cast 基本上擁有與 C 舊式轉型相同的威力與意義,以及相同的限制。例如,你不能夠利用 static_cast 將一個 struct 轉型為int,或將一個 double 轉型為 pointer;這些都是 C 舊式轉型動作原本就不可以完成的任務。static_cast 甚至不能夠移除表達式的常量性(constness),因為有一個新式轉型操作符 const_cast 專司此職。

其他新式 C++ 轉型操作符適用於更集中(范圍更狹窄)的目的。const_cast 用來改變表達式中的常量性(constness)或變易性(volatileness)。使用 const_cast, 便是對人類(以及編譯器)強調 ,通過這個轉型操作符,你唯一打算改變的是某物的常量性或變易性。這項意願將由編譯器貫徹執行。如果你將 const_cast 應用於上述以外的用途,那麼轉型動作會被拒絕。下面是個例子:

  1. class Widget { ... }; class SpecialWidget: public Widget { ... };
  2. void update(SpecialWidget *psw); SpecialWidget sw; // sw 是個 non-const 對象,
  3. const SpecialWidget& csw = sw; // csw 卻是一個代表 sw 的 reference, // 並視之為一個 const 對象。
  4. update(&csw); // 錯誤!不能將 const SpecialWidget*
  5. // 傳給一個需要 SpecialWidget* 的函數。
  6. update(const_cast(&csw)); // 可!&csw 的常量性被去除了。也因此,
  7. // csw(亦即 sw)在此函數中可被更改。
  8. update((SpecialWidget*)&csw); // 情況同上,但使用的是較難辨識
  9. // 的 C 舊式轉型語法。
  10. Widget *pw = new SpecialWidget; update(pw); // 錯誤!pw 的類型是 Widget*,但
  11. // update() 需要的卻是 SpecialWidget*。
  12. update(const_cast(pw)); // 錯誤!const_cast 只能用來影響
  13. // 常量性或變易性,無法進行繼承體系 // 的向下轉型(cast down)動作。

顯然,const_cast 最常見的用途就是將某個對象的常量性去除掉。

第二個特殊化的轉型操作符是dynamic_cast,用來執行繼承體系中"安全的向下轉型或跨系轉型動作"。也就是說你可以利用 dynamic_cast,將"指向 base class objects的pointers或references"轉型為"指向derived(或sibling base)class objects 的 pointers 或 references",並得知轉型是否成功 。如果轉型失敗,會以一個 null 指針(當轉型對象是指針)或一個 exception(當轉型對象是 reference)表現出來:

  1. Widget *pw; ...
  2. update(dynamic_cast(pw)); // 很好,傳給 update() 一個指針,指向
  3. // pw 所指的 SpecialWidget--如果 pw // 真的指向這樣的東西;否則傳過去的
  4. // 將是一個 null 指針。
  5. void updateViaRef(SpecialWidget& rsw);
  6. updateViaRef(dynamic_cast(*pw)); // 很好,傳給 updateViaRef() 的是
  7. // pw 所指的 SpecialWidget--如果 // pw 真的指向這樣的東西;否則
  8. // 拋出一個 exception。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved