Размещение Vtable полностью чисто виртуального класса

Согласно моему (ограниченному) знанию спецификации С++, виртуальная таблица класса с виртуальными членами помещается в определение первого нечистого не встроенного виртуального метода. Как компиляторы обрабатывают классы, которые наследуются от класса со ВСЕМИ чистыми виртуальными методами (например, интерфейсами)? Где находится vtable в этом случае?


person tgoodhart    schedule 06.01.2011    source источник
comment
Сама спецификация С++ ничего не говорит о виртуальных таблицах.   -  person John Dibling    schedule 06.01.2011
comment
Тяжелая деталь реализации. MSVC++ имеет __declspec(novtable) для подавления такой vtable. И нестандартное ключевое слово __interface сделать то же самое.   -  person Hans Passant    schedule 06.01.2011


Ответы (3)


В vtable хранятся адреса реализованных виртуальных методов. Если все методы класса являются чисто виртуальными и ни один из них не реализован, то генерировать виртуальную таблицу не нужно.

Вы не могли бы использовать такой класс без каких-либо классов, производных от него и реализующих методы. Каждый класс с реализованными виртуальными методами имеет свою единую виртуальную таблицу, содержащую адреса для всех виртуальных методов: она никоим образом не ссылается на виртуальные таблицы базовых классов; адреса дублируются. Поэтому, если у вас есть класс, который наследуется от другого класса, этот класс будет использовать только свою собственную виртуальную таблицу. Ему не нужна vtable базового класса; эта vtable даже не должна существовать.

Сама спецификация C++ ничего не говорит о vtables; это просто поведение компилятора, которое стало обычным явлением.

РЕДАКТИРОВАТЬ от 2020 года: я написал это почти десять лет назад. Подозреваю, что написал по памяти и личному опыту. Два комментария ниже показывают, что компиляторы делают создание виртуальных таблиц для базовых классов (для выдачи ошибок), хотя если это так, я не знаю, как вы могли бы создать для них объект, и что некоторые компиляторы действительно повторно используют виртуальные таблицы из базовые классы. Кажется, никто ничего не добавлял с 2011 года, и сейчас у меня снижение когнитивных функций, и мне трудно больше думать, так что проведите собственное исследование, если какая-то деталь здесь имеет решающее значение.

person fuzzyTew    schedule 06.01.2011
comment
Интересный. Я бы подумал, что наличие повторяющихся таблиц нарушило бы какое-то одно правило определения. - person tgoodhart; 06.01.2011
comment
Ни одна из таблиц не дублируется. Новая таблица создается только в том случае, если этим классом реализован виртуальный метод; это создает уникальную виртуальную таблицу, содержащую указатель на эту реализацию. Таблица будет содержать повторяющиеся адреса для всех неизменных виртуальных методов. - person fuzzyTew; 06.01.2011
comment
‹quote›Если все методы класса чисто виртуальные, ни один из них не реализован‹/quote› Это просто неверно. В C++ чистый виртуальный не означает отсутствие реализации. - person Ben Voigt; 06.01.2011
comment
Бен, ты прав. Я отредактировал свой ответ и проголосовал за ваш. - person fuzzyTew; 06.01.2011
comment
На самом деле компилятор будет генерировать записи для чисто виртуальных функций с заглушками ошибок, даже если они не имеют пользовательской реализации. Это делается для того, чтобы перехватывать и сообщать об ошибках при вызове чистой виртуальной функции. - person Gene Bushuyev; 06.01.2011
comment
‹quote›Каждый класс с реализованными виртуальными методами имеет свою собственную единую виртуальную таблицу, содержащую адреса для всех виртуальных методов: она никоим образом не ссылается на виртуальные таблицы базовых классов‹/quote› -- Это необязательно верно. Некоторые старые компиляторы Borland реализовывали именно указатель на базовую схему vmt для экономии памяти. Кажется, это больше никого не волнует. - person Gene Bushuyev; 06.01.2011
comment
Есть ли у GCC поведение, которое вы описываете? Где он размещает свою виртуальную таблицу для чистых виртуальных базовых классов? Было бы здорово получить правильный ответ на вопрос. - person fuzzyTew; 06.01.2011

Стандарт C++ ничего не указывает о размещении vtable или даже о существовании v-таблицы. Он просто определяет поведение, а v-таблица оказывается самой простой реализацией, поэтому широко используется.

С практической точки зрения, единственной причиной существования v-таблицы для абстрактного класса является использование во время построения и уничтожения, когда динамический тип объекта является абстрактным классом.

В классе только с чисто виртуальными функциями явно не может быть конструкторов (поскольку конструкторы не могут быть виртуальными). Однако деструкторы, безусловно, МОГУТ быть виртуальными.

В вашем классе все еще может быть чистый виртуальный деструктор с реализацией, а затем требуется v-таблица (или эквивалентные сведения о реализации).

Но реализации чисто виртуальных функций редки, и их нельзя делать при определении интерфейса.

person Ben Voigt    schedule 06.01.2011

Вам не нужна vtable, пока у вас нет экземпляра.

person JB.    schedule 06.01.2011
comment
Какой экземпляр? При компиляции одной TU компилятор не знает, будут ли чисто виртуальные функции иметь реализацию, определенную в другой TU. Разработчик компилятора может решить, как с этим справиться, и может быть разумным решением создать виртуальную таблицу и установить указатели на функцию ошибки, чтобы сообщать о незаконных вызовах неопределенных чисто виртуальных функций. - person Gene Bushuyev; 06.01.2011
comment
Прошло некоторое время с тех пор, как я написал это (уведомлен редактированием), но я полагаю, что моя точка зрения была такова: либо она абстрактна (имеет чистые виртуальные методы), следовательно, не может быть создана и не нуждается в vtable, либо нет, следовательно все унаследованные чистые виртуальные методы переопределены. Случай ОП - чисто абстрактный. Компилятор должен знать при компиляции любой TU, являются ли методы чистыми или нет, поскольку это содержится в объявлении класса. - person JB.; 20.09.2019