## polymorphic_downcast
### 頭文件: `"boost/cast.hpp"`
有時 `dynamic_cast` 被認為太過低效(的確如此)。執行`dynamic_cast`需要額外的運行時間。為了避免這些代價,常常會誘使你使用 `static_cast`, 它沒有這些性能代價。`static_cast` 用于向下轉型可能在危險的,并會導致錯誤,但它的確比`dynamic_cast`要快。如果這些加速是需要的,那我們就要確保向下轉型的安全性。`dynamic_cast` 會測試向下轉型的結果,并在失敗時返回空指針或拋出異常,而`static_cast` 則僅僅執行需要的指針運算,并將保證轉型有效的責任留給了程序員。為了確保用 `static_cast` 進行向下轉型是安全的,你必須確保對每次要執行的轉型進行測試。`polymorphic_downcast` 用`dynamic_cast`進行了轉型的測試,但僅是在調試模式下;然后它就使用 `static_cast` 去執行轉型。在發布模式下,只執行 `static_cast` 。這樣的轉型方法意味著你知道它不可能失敗,所以沒有錯誤處理,也沒有異常拋出。那么如果在非調試模式下 `polymorphic_downcast` 失敗了,會發生什么呢?未定義的行為。你的計算機可能崩潰。地球可以停止自轉。你可能飛到云上。你唯一可以肯定的是你的程序可能會發生不好的事情。如果 `polymorphic_downcast` 是在調試模式下失敗的,它對`dynamic_cast`產生的空指針執行斷言(并退出)。
在討論用`polymorphic_downcast`更換`dynamic_cast`可以如何加速你的程序之前,你應該先檢查一下設計。轉型的優化幾乎就代表著設計的問題。如果向下轉型真的是必須的,并且被證實是性能的瓶頸,`polymorphic_downcast` 就是你需要的。你可以在測試時發現錯誤的轉型,而不是在產品中(發布模式構建),如果你曾經聽到過從電話另一端傳來的用戶的尖叫,你就該知道在測試時找出錯誤是多么的重要,它使生活更輕松。很有可能你就是用戶,而且知道發現并報告別人的錯誤是多么的討厭。因此,在真正需要的時候才用 `polymorphic_downcast` ,而且要小心。
### 用法
`polymorphic_downcast` 用于那些你應該用而又不想用`dynamic_cast`的情形,原因是你確認將要發生的轉型肯定會成功,而且你需要提升它帶來的性能。注意:一定要確保使用的`polymorphic_downcast`所有可能的類型及轉換組合都經過測試。否則,不要使用 `polymorphic_downcast`; 用 `dynamic_cast` 代替它。當你決定繼續使用`polymorphic_downcast`, 包含頭文件`"boost/cast.hpp"`.
```
#include <iostream>
#include "boost/cast.hpp"
struct base {
virtual ~base() {};
};
struct derived1 : public base {
void foo() {
std::cout << "derived1::foo()\n";
}
};
struct derived2 : public base {
void foo() {
std::cout << "derived2::foo()\n";
}
};
void older(base* p) {
// Logic that suggests that p points to derived1 omitted
derived1* pd=static_cast<derived1*>(p);
pd->foo(); // <-- What will happen here?
}
void newer(base* p) {
// Logic that suggests that p points to derived1 omitted
derived1* pd=boost::polymorphic_downcast<derived1*>(p);
// ^-- The above cast will cause an assertion in debug builds
pd->foo();
}
int main() {
derived2* p=new derived2;
older(p); // <-- Undefined
newer(p); // <-- Well defined in debug build
}
```
函數`older`中的`static_cast` 會編譯成功,\[6\] 但它會帶來壞運氣,成員函數`foo`的存在使得錯誤(可能有,但不保證)被錯過,直到有人拿著一份錯誤報告,用調試器在別的地方查找奇怪的行為。當使用`static_cast`將指針向下轉型為 `derived1*`, 編譯器沒有選擇,只能相信程序員,轉型是有效的。但事實上,傳送給`older`的指針是指向一個`derived2`實例的。因此,`older`里的指針 `pd` 指向了一個完全不同的類型,這意味著什么都可能發生。這就是使用`static_cast`進行向下轉型的風險。轉型總是"成功"的,但指針可能是無效的。
> \[6\] 至少它會被編譯。
在對函數`newer`的調用里,"更好的 `static_cast`," `polymorphic_downcast` 不僅捕捉到了錯誤,并且使用斷言指出了發生錯誤的地方。當然,這僅在調試模式下是真的,使用`dynamic_cast`來測試轉型是否成功。把一個無效的轉型留在發布版本中會導致不幸。換言之,就算你在調試模式下獲得了額外的安全性,但這并不足以代表你已經試過了所有可能的轉換。
### 總結
使用`static_cast`進行向下轉換通常是危險的。你不應該這樣做,但如果一定要,使用`polymorphic_downcast`可以增加一點安全性。它在調試模式下增加了測試,可以幫助你發現轉型的錯誤,但你必須測試所有可能的轉型以確保它的安全使用。
* 如果你正在使用向下轉型并需要在發布版本中獲得`static_cast`的速度,就用 `polymorphic_downcast`; 至少在測試時你可以在出錯時得到斷言的幫助。
* 如果不能測試所有可能的轉型,就不要使用 `polymorphic_downcast`.
記住這是一種優化方法,你應該在確定需要它們時才使用。
- 序
- 前言
- Acknowledgments
- 關于作者
- 本書的組織結構
- Boost的介紹
- 字符串及文本處理
- 數 據結構, 容器, 迭代器, 和算法
- 函數對象及高級編程
- 泛 型編程與模板元編程
- 數學及數字處理
- 輸入/輸出
- 雜項
- Part I: 通用庫
- Library 1. Smart_ptr
- Smart_ptr庫如何改進你的程序?
- 何時我們需要智能指針?
- Smart_ptr如何適應標準庫?
- scoped_ptr
- scoped_array
- shared_ptr
- shared_array
- intrusive_ptr
- weak_ptr
- Smart_ptr總結
- Library 2. Conversion
- Conversion 庫如何改進你的程序?
- polymorphic_cast
- polymorphic_downcast
- numeric_cast
- lexical_cast
- Conversion 總結
- Library 3. Utility
- Utility 庫如何改進你的程序?
- BOOST_STATIC_ASSERT
- checked_delete
- noncopyable
- addressof
- enable_if
- Utility 總結
- Library 4. Operators
- Operators庫如何改進你的程序?
- Operators
- 用法
- Operators 總結
- Library 5. Regex
- Regex庫如何改進你的程序?
- Regex 如何適用于標準庫?
- Regex
- 用法
- Regex 總結
- Part II: 容器及數據結構
- Library 6. Any
- Any 庫如何改進你的程序?
- Any 如何適用于標準庫?
- Any
- 用法
- Any 總結
- Library 7. Variant
- Variant 庫如何改進你的程序?
- Variant 如何適用于標準庫?
- Variant
- 用法
- Variant 總結
- Library 8. Tuple
- Tuple 庫如何改進你的程序?
- Tuple 庫如何適用于標準庫?
- Tuple
- 用法
- Tuple 總結
- Part III: 函數對象與高級編程
- Library 9. Bind
- Bind 庫如何改進你的程序?
- Bind 如何適用于標準庫?
- Bind
- 用法
- Bind 總結
- Library 10. Lambda
- Lambda 庫如何改進你的程序?
- Lambda 如何適用于標準庫?
- Lambda
- 用法
- Lambda 總結
- Library 11. Function
- Function 庫如何改進你的程序?
- Function 如何適用于標準庫?
- Function
- 用 法
- Function 總結
- Library 12. Signals
- Signals 庫如何改進你的程序?
- Signals 如何適用于標準庫?
- Signals
- 用法
- Signals 總結