良好的设计可以完全避免铸型
Can casts be completely avoided with a good design?
我想知道是否存在完全必要的情况。
我在这里讨论的是类之间的强制类型转换,而不是基本类型。
类型转换(c++风格如static_cast
或dynamic_cast
,或普通C风格的类型转换)是代码气味吗?我知道有时它是有帮助的,但我认为它也可以避免。强制转换是否违反任何OOP规则?
不特别。应该尽可能避免强制转换,但在最基本的层面上,c++中存在类型安全领域之外的区域,因此强制转换是必要的。dynamic_cast
是一个特殊的例外,特别是,它可以是必要的,即使在一个坚实的面向对象设计。
有"那是不完美的",也有"天哪,你真蠢"。
如果代码气味您的意思是它应该在代码审查中升起一个标志,那么它们就是代码气味。如果你的意思是它们永远不应该出现在代码中,那么不,强制类型转换有一些很好的用途。
对于一个有趣的例子(我总是发现类型擦除有趣),看看boost::any
的实现,其中dynamic_cast
需要安全地从存储值中读取(不像union
,您必须猜测类型并且受到限制)
素描:
struct any_base {
virtual ~any_base() {}
};
template <typename T>
struct any_data : any_base {
T value;
any_data( T const & value ) : value(value) {}
};
struct any {
any_base * data;
any() : data() {}
~any() { delete data; }
template <typename T>
any( T const & v ) : data( new any_data<T>(v) {}
}
template <typename T>
T any_cast( any const & a ) {
any_base<T> * p = dynamic_cast< any_base<T>* >( a.data );
if ( !p ) throw invalid_cast();
return *p;
}
典型的例子是I/O:这是强制转换的少数原因之一,而且它还使用了c++中唯一合法的指针类型之一:char *
:
uint32_t n;
infile.read(reinterpret_cast<char *>(&n), sizeof n);
n *= 2;
outfile.write(reinterpret_cast<const char *>)(&n), sizeof n);
其他"类I/o"操作需要类似的模式,例如加密或编码转换。
(c++中的另一个合法指针是void *
,当在分配上下文中使用时,但它不需要强制转换:c++将内存指针"转换"为对象指针的方法是通过构造: void * addr = get_memory();
,然后是T * p = new (addr) T;
。)
我想说的是,良好的设计不能完全避免强制转换,因为在合理的情况下,强制转换是一个很好的选择。代理非常有用,通常依赖于隐式或显式强制转换,如下面的执行惰性求值。
template <class fn_t, class result_t>
class lazy_t {
fn_t fn_;
public:
lazy_t(fn_t fn) : fn_ (fn) { }
operator result_t () { return fn_(); }
};
在这种情况下,编译器可以使用隐式强制转换对给定函数执行延迟求值。我认为转换操作符是类的公共接口的一部分。
dynamic_cast<>在某些情况下也是必需的,例如实现多重分派。详见http://en.wikipedia.org/wiki/Multiple_dispatch
有时候你的程序需要复杂的代码。你不能总是坚持使用简单、基本或"干净"的语言元素。- C++避免重复声明的语法是什么
- 在没有太多条件句的情况下,我如何避免被零除
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 如何重构类层次结构以避免菱形问题
- 如何找到大小'x'数组是否完全填充,在C++?
- 类模板的成员功能的定义在单独的TU中完全专业化
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 错误处理.将系统错误代码映射到泛型
- 以下示例中如何避免代码复制?C++/库达
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 如何确保在使用基于布尔值的两个方法之一调用方法时避免分支预测错误
- 是否应该在模板化代码中完全避免const
- 链表的泛型函数remove()与成员函数remove)
- C++避免位操作完全移位
- 是否可以避免使用lambda中的尾随返回型语法
- 移动功能体,避免完全克隆
- 完全递增/递减浮点型数字
- 不完全为整型的结构和枚举
- 良好的设计可以完全避免铸型
- 文章泛型<Programming>类型化缓冲区在 C++ 11 中是否完全过时?