У всех ли классов есть Vtable, созданная для них компилятором?

#c #vtable

#c #vtable

Вопрос:

В Интернете есть много ресурсов о VTables. Обычно они имеют одинаковое утверждение относительно них:

«Всякий раз, когда сам класс содержит виртуальные функции или переопределяет виртуальные функции из родительского класса, компилятор создает vtable для этого класса. Это означает, что не у всех классов есть vtable, созданные для них компилятором. Vtable содержит указатели на функции, которые указывают на виртуальные функции в этом классе. Для каждого класса может быть только одна vtable, и все объекты одного класса будут использовать одну и ту же vtable.«

Итак, почему именно это означает, что не у всех классов есть vtable, созданные для них компилятором? Это потому, что классы somc не имеют виртуальных функций?

Ответ №1:

Точно. У некоторых классов нет vtable, потому что у них нет виртуальных методов.

Виртуальные методы — это методы, для которых ваш компилятор не может сгенерировать прямой вызов, поскольку он варьируется в зависимости от реализации класса. Vtables — это своего рода таблица поиска, которая решает эту проблему, откладывая принятие решения о том, какую реализацию вызывать во время выполнения вашей программы: вместо генерации вызова функции ваш компилятор генерирует поиск метода в vtable, затем вызывает возвращаемый метод.

Возьмем этот пример:

 class Foo
{
public:
    virtual void vMethod()
    {
        std::cout << "Foo::vMethod was called!" << std::endl;
    }
};

class Bar : public Foo
{
public:
    virtual void vMethod()
    {
        std::cout << "Bar::vMethod was called!" << std::endl;
        std::cout << "This is not the same as Foo::vMethod." << std::endl;
    }
};

Foo* foo = new Bar;
foo->vMethod();
  

Это выведет Bar сообщение. В большинстве нетривиальных сценариев ваш компилятор не может заранее знать тип объекта, для которого вызывается виртуальный метод. Как упоминалось выше, vtable решает проблему, предоставляя единый механизм поиска для поиска реализаций методов, независимо от типа объекта.

Указатель на vtable должен существовать в каждом экземпляре класса (для чего требуется размер указателя дополнительной памяти, вероятно, 4 или 8 байт) и некоторый незначительный объем статической памяти где-нибудь в адресном пространстве вашей программы. Это может показаться вам не таким уж большим (и действительно, многие люди согласятся), но это может быть громоздким в определенных сценариях (например, во встроенных системах, где объем памяти чрезвычайно ограничен). Наличие vtables для каждого класса нарушило бы общий принцип C , согласно которому вы платите только за то, что используете, и, следовательно, компилятор не генерирует никакой vtable, если в этом нет необходимости.

Отсутствие vtable имеет заметный побочный эффект отключения информации о runtime type i. Если вам нужно использовать RTTI в вашем коде, ваши классы должны иметь хотя бы один виртуальный метод. Соглашение заключается в том, чтобы в этих случаях помечать деструктор виртуальным.

Ответ №2:

На самом деле, ничто в C не требует, чтобы какой-либо класс имел vtable — это полностью проблема реализации. Однако класс с виртуальными функциями должен каким-то образом поддерживать вызовы полиморфных функций, и для этого всегда будет требоваться таблица / карта какого-либо вида. Эта таблица / карта будет создана компилятором для классов, которые имеют полиморфные функции, и может (в зависимости от качества компилятора) быть создана для тех, у кого их нет.

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

1. Знаете ли вы хоть один компилятор C , когда -либо, независимо от того, насколько плохого качества, который создавал vtables (или любой его аналог) для классов без полиморфных функций?

2. У меня нет, и для этого есть веская причина: для реализации extern "C" компилятор C должен уже поддерживать структуры без vtables. С таким же успехом можно было бы быть эффективным и создавать vtables только при необходимости.

Ответ №3:

Кроме того, у некоторых классов нет vtable, поскольку она явно удалена, см. __declspec(novtable) (зависит от компилятора)