Некоторые загадки о подобъекте в стандарте C++

Стандарт C++ определяет понятие "динамический тип" glvalue следующим образом:

динамический тип

тип самого производного объекта (1.8), на который ссылается glvalue, обозначенный выражением glvalue [Пример: если указатель (8.3.1) p, статический тип которого "указатель на класс B", указывает на объект В классе D, производном от B (раздел 10), динамический тип выражения *p равен "D." Ссылки (8.3.2) обрабатываются аналогично. - конец примера]

Как это определение интерпретируется, если то, на что ссылается glvalue, не является самым производным объектом? Означает ли это "тип самого производного объекта, который содержит объект, к которому относится значение glvalue, обозначаемое выражением glvalue"?

Еще одна загадка о 4-м абзаце в 5.7 стандарта C++:

... Если операнд-указатель указывает на элемент объекта массива, ...

Я хочу спросить, выполняется ли это условие, если операнд-указатель указывает на подобъект элемента массива. Например, если он не выполняется, то поведение в следующем коде не определено, верно?

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

3 ответа

Решение

Формулировка понятна. Предполагается, что наиболее производный объект представляет собой законченный объект, элемент данных или элемент массива, т.е. он не является подобъектом базового класса.

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 is prvalue, динамические типы glvalues ​​не рассматриваются.

Изменить: Обратите внимание, что динамические типы значений совпадают с их статическими типами.

Как это определение интерпретируется, если то, на что ссылается 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?

Да, это неопределенное поведение.

"Вопрос" может быть лучше, чем слово "загадка" здесь.

В любом случае, что касается кода, который вы показали, это довольно интересно. Это не неопределенно, так как все в этом фрагменте кода полностью определено стандартом. Однако результат не тот, который вы ожидаете, если ожидаете, что арифметика указателей будет выполнять динамическое распознавание типов.

Особенно, p укажет 2 B размеры от начала массива, а не 2 D размеры. Опять же, это совершенно четко определено. Однако доступ к этой памяти может быть недостаточно определен.

Другие вопросы по тегам