关于C++标准中的子对象的一些困惑

Some puzzles about the subobject in the C++ Standard

本文关键字:对象 C++ 标准 关于      更新时间:2023-10-16

C++标准定义glvalue的"动态类型"概念如下:

动态类型

派生最多的对象 (1.8( 的类型,glvalue 表示为 glvalue 表达式所指的类型 [示例:如果静态类型为"指向类 B 的指针"的指针 (8.3.1( p 指向派生自 B 的类 D 的对象(子句 10(,则表达式 *p 的动态类型为"D"。参考文献(8.3.2(的处理方式类似。—结束示例 ]

如果glvalue所指的不是派生最多的对象,如何解释这个定义?它是否意味着">包含由glvalue表达式表示的glvalue所指对象的最派生对象的类型"?

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

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

我想问一下,如果指针操作数指向数组对象元素的子对象,则此条件是否成立。例如,如果它不成立,则以下代码中的行为是未定义的,对吗?

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

措辞很清楚。派生最多的对象意味着是一个完整的对象、数据成员或数组元素,即它不是基类子对象。

WG21/N4527

1.8 C++对象模型

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

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

(3.1( — 如果x是一个完整的对象,那么xx的完整对象。

(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的每个操作数都是 prvalue,因此不涉及动态类型的 glvalue。

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

这里的

"问题"可能比"拼图"更好。

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

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

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

如果 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?

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