## 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 总结