向下转型基本类型

4
在C++中,如果一个基类对象被实例化为基类对象,然后向下转换为派生对象,这是否属于未定义行为?当然,我会认为这绝对必须是未定义行为,因为派生类对象可能具有基类没有的成员变量。如果将该类实例化为基类对象,则这些变量实际上不存在,这意味着通过Derived类指针访问它们必定会导致未定义行为。但是,如果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?
}

这个程序是否会造成未定义行为?

4个回答

7
是的,这仍然是未定义行为,因为您向编译器撒谎了关于d的实际类型。

请参见标准5.2.9/8:

如果存在从“指向D”的指针到“指向B”的指针的有效标准转换(4.10),则可以将类型为“指向cv1 B”的rvalue(其中B是类类型)转换为类型为“指向cv2 D”的rvalue,其中D是从B派生(第10条)的类,cv2与cv1相同或比cv1更大,且B不是D的虚拟基类。 null指针值(4.10)转换为目标类型的空指针值。如果类型为“指向cv1 B”的rvalue指向实际上是D派生类的对象的子对象B,则结果指针指向类型为D的封闭对象。否则,强制转换的结果是未定义的。

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

4
C++03标准第5.2.9.8段规定(重点在此):
当B是一个类类型时,“指向cv1 B”的右值可以转换为“指向cv2 D”的右值,其中D是从B派生(第10条)的类类型,如果存在从“指向D”的指针到“指向B”的指针的有效标准转换(4.10),则cv2与cv1相同或比cv1更严格,而B不是D的虚基类。空指针值(4.10)被转换为目标类型的空指针值。如果“指向cv1 B”的右值指向实际上是类型D对象的子对象的B,则结果指针指向类型D的封闭对象。否则,转换的结果未定义。

1

是的,那是完全未定义的行为。这就是为什么在向下转换时,除非你非常确定,否则应该优先使用dynamic_cast


2
请注意,在此示例中,由于没有虚函数,dynamic_cast 将无法工作。 - Mark B

0

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

然而,在C++中,这仍然明显是未定义行为。


嗯......对于一个非常琐碎的情况可能有效,但如果您有多重继承或多层继承等,则不一定有效。 - Richard Corden
是的...任何不平凡的事情都可能意味着基本对象在派生对象中的偏移量不为0。 我编辑了我的回复。 - 6502

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接