我控制之外的几个基类是这样的: -
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吗?
任何其他陷阱,还是我完全重新考虑设计。?
答案 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
。