Прежде всего, я хочу пояснить, что понимаю, что нет понятия vtables и vptrs в стандарте С++. Однако я думаю, что практически все реализации реализуют механизм виртуальной диспетчеризации практически так же (исправьте меня, если я ошибаюсь, но это не главный вопрос). Кроме того, я считаю, что знаю, как работают виртуальные функции, то есть я всегда могу сказать, какую функцию вызывать, мне просто нужны детали реализации.
Предположим, кто-то спросил меня следующее:
"У вас есть базовый класс 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 естественно наследует его и, следовательно, содержит его тоже. В constuctor и деструкторе B B устанавливает vptr, чтобы указать на B vtable. В конструкторе и деструкторе D D он указывает на D vtable.
Любой вызов виртуальной функции f объекта x полиморфного класса X интерпретируется как вызов x.vptr [f position in vtables]
Вопросы:
1. Есть ли ошибки в приведенном выше описании?
2. Как компилятор знает позицию f в таблице vtable (подробно, пожалуйста)
3. Означает ли это, что если класс имеет две базы, то он имеет два vptrs? Что происходит в этом случае? (попробуйте описать так же, как я, насколько это возможно)
4. Что происходит в алмазной иерархии с A сверху B, C в середине и D внизу? (A - виртуальный базовый класс B и C)
Спасибо заранее.