关于C++标准中的子对象的一些困惑
Some puzzles about the subobject in the C++ Standard
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
是一个完整的对象,那么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
的每个操作数都是 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?
是的,这是未定义的行为。
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- CMake-按正确顺序将项目与C运行时对象文件链接
- 空基优化子对象的地址
- 将对象数组的引用传递给函数
- 你能重载对象变量名本身返回的内容吗
- C++使用整数的压缩数组初始化对象
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 将对象移动到std::shared_ptr
- 代理对象的常量正确性
- 提升 ASIO 无法识别计时器对象
- 将Ref对象作为类成员
- 将包含C样式数组的对象初始化为成员变量(C++)
- 如何返回一个类的两个对象相加的结果
- 使用std::函数映射对象方法
- 是否需要删除包含对象的"pair"?
- 如何在自删除后将对象设置为nullptr
- 迭代时从向量和内存中删除对象
- 构造对象的歧义
- 使用"std::unordereded_map"映射到"std::list"对象