Виртуальная таблица в полиморфизме

Я прочитал много сообщений, и все говорят, что виртуальная таблица предназначена для каждого класса, а не для каждого объекта, а объект имеет только указатель _vtpr на общую vtable. Но, пожалуйста, рассмотрите этот пример:

class Base
{
public:
    virtual void func1(void) {}
    virtual void func2(void) {}
private:
    int dummy;
};

class Der1 : public Base
{
public:
    virtual void func1(void) {}
private:
    int dummy;
};

class Der2 : public Base
{
public:
    virtual void func2(void) {}
private:
    int dummy;
};

int main(void)
{
    Base * obj1 = new Der1;
    Base * obj2 = new Der2;
}

Связаны ли obj1 и obj2 с этим уникальным базовым классом vtable? Я считаю, что ответ отрицательный, но не могли бы вы объяснить? И если оба эти объекта относятся к одной и той же vtable, как определяется, какие методы следует вызывать? Например, ссылка obj1-> func1 отличается от ссылки obj2-> func1.

ОБНОВЛЕНИЕ:
Какие операции выполняются при выполнении Base * obj1 = new Der1;? Может кто-нибудь написать псевдокод для этих действий?


person Karolis Milieška    schedule 10.04.2016    source источник
comment
vtable не определен в стандарте C ++. Это означает, что разработчики компилятора могут делать все, что захотят. Нет даже гарантии, что vtable вообще будет. Это одна из основных причин того, почему у нас нет C ++ ABI. Скажите это всем, кто говорит.   -  person Ivan Aksamentov - Drop    schedule 10.04.2016
comment
Предположительно у Der1 и Der2 есть своя собственная vtable, не так ли?   -  person Kerrek SB    schedule 10.04.2016
comment
Конкретно проверьте этот ответ Йоханнес Шауб - litb   -  person 101010    schedule 10.04.2016
comment
@Drop, да, я это знаю. Моя ошибка заключалась в том, что я не упомянул, какая спецификация инструментальной цепочки меня интересует. И это неудивительно - GCC.   -  person Karolis Milieška    schedule 10.04.2016


Ответы (1)


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

Компилятор должен решать, как обрабатывать дублирование базового класса (если базовый класс имеет большое количество функций - будет ли производная копия всей таблицы виртуальных функций и изменять записи?). IMO, компилятор просто скопирует всю таблицу для каждого производного класса, чтобы упростить задачу. Тогда поиск подходящего метода для вызова становится простым. введите описание изображения здесь

person Ajay    schedule 10.04.2016
comment
Где и когда будут расположены новые vtables? Поправьте меня, если я ошибаюсь: при компиляции Der1 и Der2 vtables будут созданы в разделе RW data; При присвоении Base * obj1 = new Der1; и вызывая obj1- ›func1 (), Der1 vtable будет разыменован, чтобы найти запись этого конкретного метода. А поскольку Base * obj1 и obj2 - это всего лишь указатели, их нет и они копируются в vtable. - person Karolis Milieška; 10.04.2016
comment
Можете ли вы подтвердить мое понимание по этому поводу или я ошибаюсь? - person Karolis Milieška; 11.04.2016
comment
Я не знаю о разделах данных и о том, как компилятор / компоновщик точно помещает v-таблицы. Концептуально вы можете рассматривать v-таблицы как глобально связанные списки. Данный класс содержит один из заголовков v-таблицы (и, следовательно, размер класса увеличивается на sizeof(pointer)). Производный класс создаст другой связанный список v-таблицы, и класс (не экземпляр) будет указывать на этот связанный список. Если производный класс не переопределяет виртуальную функцию, он будет указывать на существующий связанный список v-таблицы. Иерархия виртуальных классов может указывать на несколько таких заголовков связанных списков, и, следовательно, размер увеличивается. Пожалуйста, прочтите книгу / онлайн - person Ajay; 11.04.2016