关于C ++标准中子对象的一些难题

时间:2015-11-06 19:19:18

标签: c++ pointers iso dynamictype subobject

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?

3 个答案:

答案 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?

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