C ++标准定义了概念"动态类型"一个glvalue如下:
动态类型
< glvalue>由glvalue表达式表示的glvalue引用的最派生对象(1.8)的类型[示例:如果指向静态类型为“指向B类的指针”的指针(8.3.1)p指向D类对象,从B(第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?
答案 0 :(得分: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
的每个操作数都是prvalue,因此不涉及动态类型的glvalues。
编辑:请注意,prvalues的动态类型与其静态类型相同。
答案 1 :(得分:0)
“问题”可能比这里的“谜题”更好。
无论如何,关于你展示的那段代码,这非常有趣。它并不是未定义的,因为该段代码中的所有内容都完全由标准定义。但是,如果您希望指针算法进行动态类型识别,那么结果就不是您所期望的。
特别是,std::cout
将指向距离数组开头2 p
个大小,而不是2个B
大小。同样,这是完全明确的。然而,访问该内存可能没有明确定义。
答案 2 :(得分:0)
如果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?
是的,这是未定义的行为。