条款 27:尽量少做转型动作
核心思想
-
尽量避免转型
- 转型通常是设计缺陷的信号。如果可能,应通过改进设计消除转型的需求。
-
优先使用 C++ 新式转型
- 新式转型(
const_cast
、dynamic_cast
、reinterpret_cast
、static_cast
)更容易辨识,并提供更明确的用途。
- 新式转型(
-
隐藏转型
- 如果转型是必要的,将其封装在函数中,减少代码中显式的转型操作。
-
避免效率低的转型
- 特别是在性能关键代码中,尽量避免使用动态转型(
dynamic_cast
)。
- 特别是在性能关键代码中,尽量避免使用动态转型(
四种新式转型
#include <iostream> #include <typeinfo> class Base { public: virtual ~Base() {} }; class Derived : public Base {}; void testCasts() { const int ci = 42; int i = const_cast<int&>(ci); // const_cast:移除常量性 std::cout << "const_cast result: " << i << std::endl; Base* base = new Derived(); Derived* derived = dynamic_cast<Derived*>(base); // dynamic_cast:安全向下转型 if (derived) { std::cout << "dynamic_cast successful" << std::endl; } else { std::cout << "dynamic_cast failed" << std::endl; } delete base; int* p = reinterpret_cast<int*>(0x1234); // reinterpret_cast:低级转型 std::cout << "reinterpret_cast result: " << p << std::endl; double d = 3.14; int j = static_cast<int>(d); // static_cast:强制隐式转换 std::cout << "static_cast result: " << j << std::endl; }
转型隐藏于函数
#include <iostream> #include <typeinfo> class Base { public: virtual ~Base() {} }; class Derived : public Base {}; // 封装 dynamic_cast Derived* safeDowncast(Base* base) { return dynamic_cast<Derived*>(base); } void testFunction() { Base* base = new Derived(); Derived* derived = safeDowncast(base); if (derived) { std::cout << "Downcast successful via safeDowncast" << std::endl; } else { std::cout << "Downcast failed via safeDowncast" << std::endl; } delete base; }
实践建议
-
通过设计避免转型
- 转型通常是对象模型设计中的缺陷信号。尝试重新设计以消除转型需求。
-
优先使用新式转型
- 避免旧式 C 风格转型 (
(type)expression
),因为它不易辨识,且没有提供明确的语义。
- 避免旧式 C 风格转型 (
-
隐藏转型
- 将转型操作封装在函数中,降低代码复杂性,提高可维护性。
-
避免性能瓶颈
- 在性能敏感的代码中,避免使用
dynamic_cast
,因为它会引入运行时开销。
- 在性能敏感的代码中,避免使用
总结
尽量少做转型动作。如果必须使用转型,遵循以下原则:
- 避免 C 风格转型,使用 C++ 新式转型。
- 将转型隐藏在函数中,避免在客户端代码中显式转型。
- 优先改进设计,消除对转型的需求。
通过遵循这些原则,可以提高代码的安全性、可维护性和效率。