2

我正在审查 C++ casts 运算符,我有以下疑问:

对于多态类

  • 二应该使用polymorphic_cast
  • 我永远不应该使用,static_cast因为向下转换可能会导致未定义的行为。无论如何,代码都会编译这种情况。

现在假设我有以下情况

class CBase{};
class CDerived : public CBase{};

int main( int argc, char** argv ){
    CBase* p = new CDerived();
    //.. do something
    CDerived*pd = static_cast<CDerived*>( p );
}

由于不涉及多态性,我不会使用polymorphic_cast,代码甚至不会编译。

如果在某个时候,有人virtual在继承树中引入了一些功能,而我现在已经意识到了,那么我就处于危险之中:我该如何实现呢?

我应该polymorphic_cast避免任何风险,但代码仍将在没有任何通知的情况下编译。

你如何意识到这种变化或防止这些情况发生?

谢谢AFG

4

3 回答 3

3

你没有包括的背景 - boost 有polymorphic_cast一个包装器dynamic_cast<>,当演员失败时抛出。 static_cast<>如果您确定数据是您要转换为的类型,那很好......无论有没有虚拟成员都没有问题,并且您包含的代码说它不会编译将编译并运行得很好是。

我猜您正在考虑意外转换为另一个派生类的可能性?这就是铸造的效用/危险,不是吗?您可以添加一个虚拟析构函数,然后使用 dynamic_cast<>,因为严格来说 RTTI 仅适用于具有一个或多个虚拟函数的类型。

使用 static_cast<> 编写的代码将继续安全地处理同一类型,而不管是否引入了虚函数......只是如果您开始将该代码传递给其他类型(即不是 CDerived 或任何从其公开派生的),那么您将需要dynamic_cast<> 或其他一些更改以防止不兼容的操作。

于 2010-10-25T08:46:05.177 回答
1

当您处理指针 p(CBase* 类型)时,指向的对象将被视为 CBase,但所有虚函数都会做正确的事情。指针 pd 将相同的对象视为 CDerived。以这种方式向上转换是危险的,因为如果对象不是从向上转换的类型派生的,则向上转换对象的任何额外成员数据都将丢失(这意味着您将在一些其他数据中四处寻找),并且虚函数查找将是一切都搞砸了。这与向下转换(如您已标记此问题)相反,您可能会得到slicing

为了避免这种情况,你需要改变你的编程风格。将同一对象视为两种不同类型是一种可疑的做法。C++ 可以非常擅长强制执行类型安全,但如果你真的想要,或者只是不知道更好,它会让你摆脱讨厌的事情。如果您想根据对象类型做不同的事情,并且不能通过虚函数(例如通过双分派)来完成,您应该更彻底地研究 RTTI(看这里,或者看一些好的例子这里)。

于 2010-10-25T09:01:50.197 回答
0

polymorphic_cast 未在 C++ 中定义。你在考虑dynamic_cast吗?

无论如何,你不能做任何事情来阻止它。

于 2010-10-25T08:42:48.470 回答