2010-06-15 43 views
10

在这一点上,我对C++的了解比其他任何东西都更具学术性。在我所有的阅读迄今为止,使用一个名为强制类型转换(const_caststatic_castreinterpret_castdynamic_cast)显式转换来了一个大警告标签(这很容易明白为什么),这意味着显式转换是对症糟糕的设计和只能在绝望的情况下作为最后的手段使用。所以,我要问:C++显式转换真的很糟吗?

与名为显式转换蒙上真的只是陪审团舞弊代码或者是有一个更优雅,积极应用到这个功能吗?后者有一个很好的例子吗?

回答

19

有些情况下,你不能没有它。像this one。这个问题有,你有多重继承,需要this指针转换void*同时确保该进入void*指针仍将指向当前对象的右侧子对象。使用明确的转换是实现这一目标的唯一方法。

有一种观点认为,如果你不能没有演员,你的设计就不好。我完全同意这一点 - 不同的情况是可能的,包括上面提到的一种情况,但也许如果你需要经常使用明确的演员阵容,那么你确实有不好的设计。

+9

我同意sharptooth在这里的最终评论,仅仅因为你有一个明确的转换并不意味着你有错误的代码,但是如果你每隔一行转回去转发,那么你需要重新思考。铸造是一种有效的操作,但它不应该被过度使用。 – 2010-06-15 13:45:50

+1

当然从来没有用过摆脱编译警告和错误! – Alan 2010-06-15 16:26:31

11

有些情况下,您无法避免显式强制转换。尤其是在与C库或设计错误的C++库(如COM库作为示例使用的锐利库)交互时。

一般来说,使用显式演员是一个红色的鲱鱼。它并不一定意味着不好的代码,但它确实吸引人们注意潜在的危险用途。

但是,您不应该将4个演员放在同一个包中:static_castdynamic_cast经常用于上演(从基础派生到派生)或在相关类型之间进行导航。它们在代码中的出现是非常正常的(实际上,如果没有其中的任何一个,就很难编写Visitor模式)。

在另一方面,利用const_castreinterpret_cast是更危险的。

  • 使用const_cast尝试修改只读对象是不确定的行为(感谢詹姆斯McNellis修正)
  • reinterpret_cast通常只用来处理原始内存(分配器)

当然,它们有它们的用途,但不应在正常代码中遇到。对于处理外部或C API,它们可能是必要的。

至少这是我的意见。

+1

从技术上讲,它只是通过'const_cast'的结果修改一个只读对象,导致未定义的行为。 'const_cast'本身是“安全的”。 – 2010-06-15 14:18:59

+0

谢谢,我相应地调整了句子。有效地,任何强制转换本身都是安全的,它只使用可能引发未定义行为的结果。 – 2010-06-15 14:35:06

+0

COM不是C++库,因此没有考虑到良好的C++语义。这并没有让它变得糟糕 - 它只是定义了它自己的对象模型。 (COM是*其他*理由PITA) – 2010-06-15 15:22:00

3

海事组织,像大多数事情一样,它们是工具,具有适当的用途和不适当的用途。铸造可能是其中的工具经常得到使用不当,例如,具有reinterpret_cast(可在平台上,其中两个是不同的尺寸打破),或const_cast远常量性纯粹作为一个黑客的int和指针类型之间施放的区域, 等等。

如果你知道他们是什么和预期用途,但绝对没有错,他们使用什么他们设计的。

6

演员阵容多么糟糕通常取决于阵容的类型。所有这些演员阵容都有合法的用途,但有些人的气味比其他人差。

const_cast用于铸造const(因为添加它不需要转换)。理想情况下,永远不要使用。它可以很容易地调用未定义的行为(尝试更改最初指定为const的对象),并且在任何情况下都会中断const-程序的正确性。有时需要与本身不是const的API进行接口时,它可能会要求char *将它当作const char *,但由于您不应该以这种方式编写API,所以它是您的标志'正在使用一个非常旧的API或者有人搞砸了。

reinterpret_cast总是要取决于平台,因此在可移植代码中最好是有问题的。而且,除非您对物体的物理结构进行低级别操作,否则不会保留意义。在C和C++中,类型应该是有意义的。一个int是一个数字,意味着什么;一个int这基本上是连接的char s并不意味着什么。

dynamic_cast通常用于向下转换;例如从Base *Derived *,条件是要么它工作,要么返回0.这颠覆OO的方式与类型标记中的switch语句非常相似:它移动定义类与类定义不同的代码。这将类定义与其他代码结合起来并增加了潜在的维护负载。

static_cast用于已知通常是正确的数据转换,例如从void *转换到类别层次结构中已知的安全指针类型转换等等。关于最糟糕的是你可以说它在某种程度上颠覆了类型系统。当与C库或标准库的C部分接口时,可能需要使用它,因为经常在C函数中使用void *。一般来说,设计良好且编写良好的C++代码将避免上述用例,在某些情况下,因为只有使用cast会做潜在的危险事情,而在其他情况下,因为这样的代码往往会避免这种转换的需要。 C++类型的系统通常被认为是一件好事,并且会将其颠覆。

1

明确的演员有一个讽刺。开发人员的C++设计技能很差,导致他编写需要大量投射的代码的是同一开发人员,他们没有适当地使用显式投射机制,或者根本不使用显式投射机制,并将其代码与C风格演员混为一谈。另一方面,理解他们的目的,什么时候使用它们,何时不使用,以及替代方案的开发人员不会编写需要大量投射的代码!


检查出这些类型转换的更细粒度的变化,如polymorphic_cast,在升压转换库,给你的程序员是多么小心C++是当它涉及到铸造的想法。

1

铸件是一种标志,表示您正试图在方孔中放置一个圆钉。有时候这是工作的一部分。但是如果你对孔洞和钉子都有一定的控制力,最好不要创造这种条件,写剧本应该引发你问自己是否有某件事情可以做,这样会更平滑。