2010-10-25 43 views
2

我检讨C++蒙上运营商,我有以下疑问:的static_cast时,基地不变成多态多形性

多态类

  • II应该使用polymorphic_cast
  • 我应该从不使用static_cast,因为向下投射可能会导致未定义的行为。代码无论如何编译这个案例。

现在假设我有以下situtation

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

+0

*并且代码甚至不会编译* - 你的意思是*并且代码会编译好*? – 2010-10-25 08:38:59

+1

不应该为CBase“析构”虚拟吗?在这种情况下,你可以使用'dynamic_cast'或'polymorphic_cast'。 – Naveen 2010-10-25 08:40:30

+2

在标准C++中没有'polymorphic_cast'这样的东西。为什么不首先使用'CDerived'?或者如果你认为你必须使用动态分配,为什么不使用'CDerived *'?虚拟功能即使在不知情的情况下也不会造成任何危险。那些类名称上的所有这些“C”前缀是什么?这听起来像是一个严重的口吃我的情况。干杯, – 2010-10-25 08:46:22

回答

3

背景,你不包括 - 升压具有polymorphic_cast围绕dynamic_cast<>的包装时,转换失败抛出。 static_cast<>很好,如果你确定数据的类型是你正在投入的......没有或没有虚拟成员没有问题,你所包含的代码说它不会编译将编译和运行就好原样。

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

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

+0

Hi Tony!我喜欢这个想法。虚拟到析构函数默认情况下会阻止我的问题,同时我也不会泄露任何东西。非常感谢! – 2010-10-25 09:49:29

+0

@ abruzzo-forte-e-gentile:我知道很多人选择这样做(默认情况下为虚拟析构函数) ,但要注意这里有一些代价,它很小,但我认为你应该只使用析构函数虚拟,如果你期望类使用多态(即在至少另一种方法也被宣布为病毒)。 – beldaz 2010-10-28 03:00:22

0

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

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

+0

'boost'具有'polymorphic_cast',我猜OP正在使用它。 – Naveen 2010-10-25 08:44:35

1

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

为了避免这种情况,你需要改变你的编程风格。把两个不同类型的对象作为一个可疑的练习。 C++在执行类型安全方面非常出色,但如果你真的想要,或者只是不知道更好,它可以让你摆脱讨厌的东西。如果你想根据对象类型做不同的事情,并且不能通过虚拟功能(例如通过double dispatch)来完成,你应该更深入地了解RTTI(look here,或者查看一些很好的例子here)。