Вопрос

Прежде всего, я хочу прояснить, что Я понимаю, что нет понятия vtables и vptrs в стандарте C ++. Отказ Однако я думаю, что практически все реализации реализуют виртуальный механизм отправки в значительной степени так же (поправьте меня, если я ошибаюсь, но это не главный вопрос). Кроме того, я верю Я знаю, как работают виртуальные функции, То есть я всегда могу сказать, какая функция будет называться, мне просто нужны детали реализации.

Предположим, кто-то спросил меня следующее:
«У вас есть базовый класс B с виртуальными функциями v1, v2, v3 и полученный класс d: b, который переопределяет функции v1 и v3 и добавляет виртуальную функцию v4. Объясните, как работает виртуальные рассылки».

Я бы ответил так:
Для каждого класса с виртуальными функциями (в данном случае B и d) у нас есть отдельный массив указателей к функциям, называемым VTable.
VTable для B будет содержать

&B::v1
&B::v2
&B::v3

VTable для D будет содержать

&D::v1
&B::v2
&D::v3
&D::v4 

Теперь класс B содержит указатель участника VPTR. D Естественно наследует его и поэтому содержит его тоже. В конструкторе и деструктора BB устанавливает VPTR, чтобы указать на VTable B. В конструкторе и деструктор DD устанавливает его, чтобы указать на VTable.
Любой призыв к виртуальной функции F на объекте X полиморфного класса X интерпретируется как вызов X.VPTR [положение F в VTTable

Вопросы:
1. Есть ли у меня какие-либо ошибки в приведенном выше описании?
2. Как компилятор знает позицию F в VTable (подробно, пожалуйста)
3. Значит ли это, что если у класса есть два база, то у него есть два VPTR? Что происходит в этом случае? (Попробуйте описать аналогичным образом, так как я сделал как можно больше деталей)
4. Что происходит в алмазной иерархии с на вершине B, C в середине и D на дне? (A - это виртуальный базовый класс B и C)

Заранее спасибо.

Это было полезно?

Решение

1. Есть ли у меня какие-либо ошибки в приведенном выше описании?

Все хорошо. :-)

2. Как компилятор знает позицию F в VTable

Каждый поставщик будет иметь свой собственный способ сделать это, но я всегда думаю о VTable в качестве карты подписи функции участника к смещению памяти. Таким образом, компилятор просто поддерживает этот список.

3. Значит ли это, что если у класса есть два база, то у него есть два VPTR? Что происходит в этом случае?

Как правило, компиляторы составляют новый VTable, который состоит из всех VTBable из виртуальных баз, добавленных вместе в том порядке, наряду с VTable указателем виртуальной базы. Они следуют за этим с помощью VTable функций полученного класса. Это очень сильно специфический поставщик, но для class D : B1, B2, вы обычно видите D._vptr[0] == B1._vptr.

multiple inheritance

Это изображение фактически для составления полей элементов объекта, но VTables может быть составлен компилятором точно так же (насколько я понимаю).

4. Что происходит в алмазной иерархии с на вершине B, C в середине и D на дне? (A - это виртуальный базовый класс B и C)

Короткий ответ? Абсолютный ад Вы практически наследули как базы? Только один из них? Никто из них? В конечном итоге используются те же методы составления VTable для класса, но как это делается варьируется в зависимости от способа дико, поскольку как Это должно быть сделано совсем не набор в камне. Существует достойное объяснение решения проблемы алмазной иерархии здесь, но, как и большинство из этого, это довольно поставщик.

Другие советы

  1. Выглядит хорошо для меня
  2. Конкретная реализация, но большинство из них только в порядке исходного кода - то есть порядок, который они появляются в классе - начиная с базового класса, затем добавляя новые виртуальные функции из полученного. Пока компилятор имеет детерминированный способ сделать это, то все, что он хочет сделать, это в порядке. Однако в Windows, для создания COM совместимых V-таблиц, он должен быть в порядке источника

  3. (Точно сказать не могу)

  4. (Угадайте) Алмаз просто означает, что у вас могут быть два копии базового класса B. Виртуальное наследование будет объединять их в один экземпляр. Поэтому, если вы установите члена через D1, вы можете прочитать его через D2. (С C, полученным из D1, D2, каждый из них получен из б). Я считаю, что в обоих случаях VTables будет идентична, поскольку указатели функции одинаковы - память для членов данных - это то, что объединено.

Комментарии:

  • Я не думаю, что разрушители приходят в это!

  • Звонок, такой как например, D d; d.v1(); Вероятно, не будет реализован через vTable, так как компилятор может разрешить адрес функции при компиляции / канала-времени.

  • Компилятор знает fПоложение, потому что он там положил!

  • Да, класс с несколькими базовыми классами обычно будет иметь несколько VPTR (при условии виртуальных функций в каждом базовом классе).

  • Скотт Мейерс «Эффективные C ++» книги «C ++» объясняют многократное наследование и бриллианты лучше, чем я могу; Я бы порекомендовал читать их для этого (и многих других) причин. Рассмотрим их важное чтение!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top