在C ++中,如果基类对象被实例化作为基础对象,并且随后向下转换为派生对象,那么它是未定义行为吗?
当然,我认为肯定必须是未定义的行为,因为Derived类对象可能具有基类不具有的成员变量。因此,如果将类实例化为基础对象,则这些变量实际上不存在,这意味着通过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?
}
此程序是否会导致未定义的行为?
答案 0 :(得分:7)
是的,它仍然是未定义的行为,因为你对编译器说谎d
的实际类型。
见标准5.2.9 / 8:
“指向cv1 B的指针”类型的右值, 其中B是类类型,可以 转换为类型的右值 “指向cv2 D的指针”,其中D是一个类 如果有效,则从B派生(第10条) 标准转换从“指针到 D“到”指向B的指针“存在(4.10), cv2与cvqualification相同,或 比cv1更高的资格认证 B不是D的虚拟基类。 空指针值(4.10)是 转换为空指针值 目的地类型。如果是左值 键入“指向cv1 B的指针”指向B 这实际上是一个子对象 D型对象,由此产生 指针指向封闭对象 D型。否则,结果 演员阵容未定义。
最后两句话说如果指针指向的B
实际上不是D
派生类的一部分,那么强制转换是未定义的行为。
答案 1 :(得分:4)
C ++ 03标准,参与。 5.2.9.8列出(强调我的):
“指向cv1 B的指针”类型的右值, 其中B是类类型,可以 转换为类型的右值 “指向cv2 D的指针”,其中D是一个类 如果有效,则从B派生(第10条) 标准转换从“指针到 D“到”指向B的指针“存在(4.10), cv2与cv资格相同, 或者更高的cv资格,比cv1, 和B不是虚拟基类 D.空指针值(4.10)是 转换为空指针值 目的地类型。 如果是rvalue 键入“指向cv1 B的指针”指向B 这实际上是一个子对象 D型对象,由此产生 指针指向封闭对象 D型。否则,结果 演员阵容未定义。
答案 2 :(得分:1)
是的,这是完全未定义的行为。这就是为什么在向下倾斜时你应该支持dynamic_cast
,除非你非常肯定。
答案 3 :(得分:0)
鉴于我在生成的机器代码方面的C ++实现的心智模型,我会说如果调用的方法不是虚拟的,并且派生类在基类没有时引入虚方法,并且多重继承是如果方法代码确实只访问在基础对象中定义的成员,那么它应该按照您的预期工作。
然而,这仍然是C ++中的UB。