Схема хранения полиморфных объектов по стандарту C++

Я знаю, что если класс содержит какие-либо виртуальные функции, большинство компиляторов (если не все) добавляют к его объектам указатель vptr. Кто-то добавляет его первым элементом, кто-то последним. Но требует ли стандарт C++ использование vptr и vtable? Может ли какой-либо компилятор теоретически реализовать это каким-либо другим способом? Если да, то каковы гарантии в отношении схемы хранения полиморфных объектов и общего размера (например, все ли явно определенные поля (+ заполнение) в непрерывном блоке памяти)?

Я не знаю, различается ли это между различными стандартами C++, поэтому я добавил только общий тег C++.


person NPS    schedule 17.03.2020    source источник
comment
100% зависит от компилятора (или, если хотите, зависит от ABI)   -  person curiousguy    schedule 17.03.2020


Ответы (1)


В стандарте C++ нет ничего, что предписывало бы конкретную реализацию виртуального наследования. Семантика виртуального наследования определяется соответствующим синтаксисом и ожидаемыми результатами. Реализации C++ могут свободно использовать любую техническую реализацию, которая дает такие результаты.

Например, начнем с виртуального наследования целых базовых классов:

[класс.ми]

Спецификатор базового класса, содержащий ключевое слово virtual, задает виртуальный базовый класс. ... Для каждого отдельного базового класса, который указан как виртуальный, наиболее производный объект должен содержать один подобъект базового класса этого типа.

Стандарт определяет синтаксис virtual как введение виртуального наследования базового класса и ожидаемый результат: наиболее производный объект содержит единственный экземпляр виртуально унаследованного базового класса. Полная остановка. Конец истории. Как конкретная реализация делает это, выходит за рамки стандарта.

Аналогично для отдельных виртуальных функций:

[класс.виртуальный]

Если виртуальная функция-член vf объявлена ​​в классе Base и в классе Derived, производном прямо или косвенно от Base... [еще несколько требований]... тогда Derived::vf... переопределяет Base::vf.

Некоторые технические требования опущены. Стандарт просто указывает, что виртуальная функция в производном классе «переопределяет» (ту же) функцию в базовом классе. Как конкретная реализация C++ делает это, нигде не указано.

person Sam Varshavchik    schedule 17.03.2020
comment
Верно, но вопрос был не о виртуальном наследовании, реализация которого сильно различается. Теоретически виртуальные функции могут быть реализованы по-разному, но на практике в общих принципах существует единообразие: виртуальные функции всегда реализуются с v/ptr и vtables. - person curiousguy; 17.03.2020
comment
Означает ли это, что никогда нельзя зависеть от схемы хранения объектов (или, по крайней мере, объектов с виртуальными функциями)? Я имею в виду, если чего-то нет в стандарте, то программа не должна полагаться на это? - person NPS; 18.03.2020
comment
@NPS Зачем вообще заботиться о том, каков точный макет? Разобраться в таких вещах, как содержимое виртуальной таблицы, для любой нетривиальной иерархии чрезвычайно сложно; это при условии, что вы не против отказаться от портативности. - person curiousguy; 18.04.2020