унаследованы ли vptr и vtable от базового класса?

Как видно, D3 представляет новую виртуальную функцию @function3() в середине цепочки наследования. Мне интересно, что происходит с *--vptr и vtable, когда это происходит. D3 теперь является своего рода новым базовым классом,

class Base {
public:
    virtual void function1() { std::cout << "Base func1()\n"; };
    virtual void function2() { std::cout << "Base func2()\n"; };
};

class D1 : public Base {
public:
    virtual void function2() { std::cout << "D1 func2()\n"; };
};

class D2 : public D1 {
public:
    virtual void function1() { std::cout << "D2 func1()\n"; };
};

class D3 : public D2 {
public:
    virtual void function2() { std::cout << "D3 func2()\n"; };
    virtual void function3() { std::cout << "D3 func3()\n"; };
};

class D4 : public D3 {
public:
    virtual void function1() { std::cout << "D4 func1()\n"; };
    virtual void function3() { std::cout << "D4 func3()\n"; };
};

int main() {
    D3 d3;  
}

https://imgur.com/a/sxFzrKG

но когда я вижу записи vtable, я вижу function1(), function2(). Я думал, записи должны быть function2(), function3(). Почему я не могу получить то, что я думал?


person meng    schedule 12.08.2019    source источник
comment
ПРИМЕЧАНИЕ. vptr/vtable — это детали реализации. Имплантации не должны должны использовать их для реализации виртуальной диспетчеризации (хотя большинство из них это делают) — они могут свободно использовать другие методы для достижения стандартного обязательного поведения, если они того пожелают. Компилятор также может пропустить код для вещей, которые, как он может доказать, на самом деле никогда не нужны.   -  person Jesper Juhl    schedule 12.08.2019
comment
Добавьте код, который вызывает d3.function1(), d3.function2() и d3.function3(). Проверьте разборку. Что ты видишь?   -  person Jeffrey    schedule 12.08.2019
comment
Возможно, отладчик показывает только две записи, потому что Base содержит только две записи. Будет дополнительная запись для function3, которая не отображается (или может быть ниже нижней части окна; проверьте полосу прокрутки).   -  person 1201ProgramAlarm    schedule 12.08.2019
comment
@ 1201ProgramAlarm Или компилятор просто оптимизировал его, поскольку он никогда не использовался.   -  person Jesper Juhl    schedule 12.08.2019
comment
Несвязанный: после объявления функции virtual она становится виртуальной во всех производных классах (но также см. final< /а>). Для вас это означает, что вам не нужно постоянно повторять virtual.   -  person user4581301    schedule 12.08.2019
comment
override удобен для использования с этими виртуальными методами однако в производных классах.   -  person Shawn    schedule 12.08.2019
comment
@JesperJuhl Как можно оптимизировать (некоторые) виртуальные функции?   -  person curiousguy    schedule 13.08.2019
comment
@curiousguy Бывают ситуации, когда компилятор может доказать, что они никогда не использовались полиморфно. В качестве крайнего примера рассмотрим класс final, определенный в исходном файле.   -  person Jesper Juhl    schedule 13.08.2019
comment
@JesperJuhl Как финал что-то доказывает?   -  person curiousguy    schedule 13.08.2019
comment
@curiousguy Он сообщает компилятору, что никакой другой класс не может наследоваться от класса final. Таким образом, любые функции virtual, очевидно, не могут быть переопределены. Таким образом, компилятору не нужно учитывать виртуальную диспетчеризацию.   -  person Jesper Juhl    schedule 13.08.2019
comment
@JesperJuhl Да, но тогда что это изменит для самих vptr/vtable?   -  person curiousguy    schedule 13.08.2019


Ответы (2)


Виртуальная таблица содержит все унаследованные виртуальные функции и любые вновь введенные.

Вот виртуальная таблица для D3, сгенерированная MSVC:

const D3::`vftable' DD  FLAT:const D3::`RTTI Complete Object Locator'  ; D3::`vftable'
        DD      FLAT:virtual void D2::function1(void)
        DD      FLAT:virtual void D3::function2(void)
        DD      FLAT:virtual void D3::function3(void)

Причина, по которой отладчик не показывает их все, может быть ошибкой или ограничением.

person krisz    schedule 12.08.2019
comment
Не могли бы вы подсказать, как создать vtable с помощью MSVC? - person meng; 13.08.2019

Не совсем понятно, что вы подразумеваете под «что происходит». Все vtable относятся к классу (типу). vtable для D1 отличается от vtable для D2 и так далее.

Vtable для D3 имеет больше функций, чем D1. Обычно вы можете вызывать эти функции, если ваш статический тип D3 или D4, но не можете вызывать их, если ваш статический тип D1 или D2.

person SergeyA    schedule 12.08.2019