向下转换基类型

Downcasting a base type

本文关键字:类型 基类 转换      更新时间:2023-10-16

在C++中,如果基类对象实例化为基对象,随后向下转换为派生对象,是否为未定义行为?

当然,我认为它肯定必须是未定义的行为,因为派生类对象可能具有基类没有的成员变量。 因此,如果类被实例化为基对象,这些变量实际上将不存在,这意味着通过派生类指针访问它们必须导致未定义行为。

但是,如果 Derived 类只提供额外的成员函数,但不包含任何进一步的成员数据,该怎么办? 例如:

class Base
{
    public:
    int x;
};
class Derived : public Base
{
    public:
    void foo();    
};
int main()
{
    Base b;
    Derived* d = static_cast<Derived*>(&b);
    d->foo(); // <--- Is this undefined behavior?
}

此程序是否会导致未定义的行为?

是的,它仍然是未定义的行为,因为您在真正的d类型上向编译器撒谎。

请参阅标准 5.2.9/8:

类型为"指向 cv1 B 的指针"的右值, 其中 B 是类类型,可以是 转换为类型的右值 "指向 cv2 D 的指针",其中 D 是一个类 从B派生(第10条),如果有效 从"指针到 D"到"指向 B"的指针存在 (4.10), CV2 与 CV资格相同,或 CV资格高于CV1,以及 B 不是 D 的虚拟基类。 空指针值 (4.10) 为 转换为空指针值 目标类型。如果右值 类型"指向 cv1 B 的指针"指向 B 这实际上是 类型 D 的对象,结果 指针指向封闭对象 类型为 D。否则,结果为 强制转换未定义。

最后两句话说,如果指针指向的B实际上不是D派生类的一部分,则强制转换是未定义的行为。

C++03 标准第 5.2.9.8 段对此进行了阐述(强调我的):

类型为"指向 cv1 B 的指针"的右值, 其中 B 是类类型,可以是 转换为类型的右值 "指向 cv2 D 的指针",其中 D 是一个类 从B派生(第10条),如果有效 从"指针到 D"到"指向 B"的指针存在 (4.10), CV2 与 CV 资格相同, 或比CV1更高的CV资格, 和 B 不是 的虚拟基类 D.空指针值 (4.10) 为 转换为空指针值 目标类型。如果右值 类型"指向 cv1 B 的指针"指向 B 这实际上是 类型 D 的对象,结果 指针指向封闭对象 类型为 D。否则,结果为 强制转换未定义。

是的,这是完全未定义的行为。这就是为什么在贬低时,你应该偏袒dynamic_cast,除非你非常非常确定。

鉴于我对生成的机器代码C++实现的心智模型,我会说,如果调用的方法不是虚拟的,并且派生类没有引入虚拟方法,而基类没有,并且多重继承不涉及这种诡计和......如果方法代码确实只访问 Base 对象中定义的成员,它应该按预期工作。

然而,这在C++中仍然很明显是UB。