我无法控制几个基类,例如:
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?还有其他陷阱,还是我要完全重新考虑设计?
最佳答案
这样的垂降必须格外小心:它很容易导致UB。
该标准保证您可以安全地从MyNode*
转换为BaseNode*
:
但是,让我们一起玩火:该标准还允许您在特定条件下从BaseNode*
转换为MyNode*
:
我尝试将这些引号翻译成纯文本:
BaseHost::getNode()
返回指向MyNode
对象的向上转换的指针,并且在类层次结构中没有虚拟继承,则可以。 BaseHost::getNode()
会返回其他内容(例如,指向纯BaseNode
或另一个BaseNode
的同级衍生物的指针),则您将拥有UB。 如上所述,这很危险:UB可能已经在指针转换期间发生,甚至在尝试取消引用指针之前。因此最好避免这种情况。如果您有一个多态的
BaseNode
类(例如带有虚拟析构函数的类),则可以使用更安全的 dynamic_cast
。