对象切片或UB风险?

时间:2016-06-26 11:36:21

标签: c++ inheritance undefined-behavior

我控制之外的几个基类是这样的: -

class BaseNode // Just a POD class. No VTable
{
  void foo();
}

class BaseHost 
{
public:
  BaseNode *getNode()
  {
    ...
  } 
}

我想"延伸" BaseNode::foo的功能,但课程有效密封。

以下是建议: -

class MyNode: public BaseNode 
{
  void foo()
  {
    // do my stuff..., then
    BaseNode::foo();
  }    
}

class MyHost: public BaseHost 
{
public:
  MyNode *getNode()
  {
    return (MyNode*) BaseHost::getNode(); // Slicing or UB risk?
  }   
}

如果MyNode引入了额外的类成员或虚拟方法,那么事情将会出现严重错误 - 但如果满足这些限制,我还有UB吗?

任何其他陷阱,还是我完全重新考虑设计。?

1 个答案:

答案 0 :(得分:1)

这种向下转型应谨慎使用:它很容易导致UB。

该标准保证您可以安全地从MyNode*转换为BaseNode*

  

4.10 / 3:类型为“指向cv D的指针”的prvalue,其中D是类类型,可以转换为类型为“指向cv B的指针”的prvalue,其中B   是D的基类。如果B是不可访问或模糊的基类   D,需要这种转换的程序是不正确的。该   转换的结果是指向基类子对象的指针   派生类对象。空指针值转换为   目标类型的空指针值。

但让我们玩火:标准也让你可以在某些条件下从BaseNode*投射到MyNode*

  

5.2.9 / 11:类型为“指向cv1 B的指针”的prvalue,其中B是类类型,可以转换为类型为“指向cv2 D的指针”的prvalue,其中   D是从B派生的类,如果是有效的标准转换   “指向D的指针”到“指向B的指针”存在,cv2是相同的   cv-qualification为,或者比cv1更高的cv资格,而B是   既不是D的虚拟基类,也不是虚拟基类D 的基类。空指针值转换为空指针   目的地类型的值。 如果类型“prvalue”指向   cv1 B“指向B,它实际上是类型对象的子对象   D,结果指针指向D类型的封闭对象。   否则,行为未定义

我尝试将这些引号翻译成纯文本:

  • 如果您确定BaseHost::getNode()返回指向MyNode对象的上传指针,并且您的类层次结构中没有虚拟继承,那么它就可以了。
  • 但如果BaseHost::getNode()会返回其他内容(例如指向普通BaseNode的指针或BaseNode的另一个兄弟衍生物),那么您将拥有UB。

如上所述,它很危险:在您尝试取消引用指针之前,UB可能已经在指针转换期间发生。所以最好尽量避免它。如果您拥有多态BaseNode类(例如使用虚拟析构函数),则可以使用更安全的dynamic_cast