1

C++ 标准定义了泛左值的概念“动态类型”,如下所示:

动态型

<glvalue> 由glvalue 表达式表示的glvalue 所指的最衍生对象(1.8)的类型[示例:如果静态类型为“指向B 类的指针”的指针(8.3.1)p 指向的对象为D 类,派生自 B(第 10 条),表达式 *p 的动态类型是“D”。参考文献(8.3.2)的处理方式类似。—结束示例]

如果泛左值所指的不是最衍生的对象,如何解释这个定义?这是否意味着“包含由glvalue表达式表示的glvalue所指的对象的最派生对象的类型”?

另一个难题是关于 C++ 标准 5.7 中的第 4 段:

...如果指针操作数指向数组对象的元素,...

我想问如果指针操作数指向数组对象元素的子对象,这个条件是否成立。举个例子,如果它不成立,那么下面代码中的行为是未定义的,对吧?

D d[10];
B *p = d; //B is a base class of D
p += 2;   //undefined behavior?
4

3 回答 3

1

措辞很清楚。最派生对象暗示为完整对象、数据成员或数组元素,即它不是基类子对象。

WG21/N4527

1.8 C++ 对象模型 [intro.object]

2 对象可以包含其他对象,称为子对象。子对象可以是成员子对象(9.2)、基类子对象(第 10 条)或数组元素。不是任何其他对象的子对象的对象称为完整对象。

3 对于每个对象x,都有一个对象称为 的完整对象x确定如下:

(3.1) — 如果x是完整对象,则x是 的完整对象x

(3.2) — 否则, 的完整对象x是包含 的(唯一)对象的完整对象x

4 如果一个完整的对象,一个数据成员(9.2),或者一个数组元素是类类型,它的类型被认为是最派生类,以区别于任何基类子对象的类类型;最派生类类型或非类类型的对象称为最派生对象

D d[10];
B *p = d; //B is a base class of D
p += 2;   //undefined behavior?

毫无疑问,这具有未定义的行为。没有关于派生类的附加规则。并且由于表达式的每个操作数p += 2都是纯右值,因此不涉及动态类型的泛左值。

编辑:请注意,纯右值的动态类型与其静态类型相同。

于 2015-11-07T13:27:10.173 回答
0

这里的“问题”可能比“谜题”更好。

无论如何,关于你展示的那段代码,这很有趣。它不是未定义的,因为那段代码中的所有内容都完全由标准定义。但是,如果您希望指针算术进行动态类型识别,结果不是您所期望的。

特别是,p将指向B距离数组开头 2 个大小,而不是 2 个D大小。同样,这是完全定义好的。然而,访问该内存可能没有很好的定义。

于 2015-11-06T19:29:25.177 回答
0

如果泛泛值所指的不是最派生的对象,如何解释这个定义?

如果glvalue引用一个有效的对象,它总是构造的最派生的对象,不一定是基类型的最派生的类型。

例子:

class Base {};
class Derived1 : public Base {};
class Derived2 : public Derived1 {};

Base* ptr = new Derived1;

*ptr指的是Derived1,不是Derived2因为构造的对象是类型的Derived1

D d[10];
B *p = d; //B is a base class of D
p += 2;   //undefined behavior?

是的,这是未定义的行为。

于 2015-11-06T19:30:56.380 回答