Сколько виртуальных таблиц создается для следующего кода?

#c #vtable

#c #vtable

Вопрос:

Я изучаю c и получил один вопрос о виртуальной таблице, помогите мне понять это. Я хочу знать, сколько таблиц создано в этой программе.

  #include <iostream>
    class A { public: virtual void f() { } };
    class B : public A { };
    class C : public B { };
  

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

1. Предполагая, что созданы какие -либо vtables (это деталь реализации компилятора, не продиктованная стандартом), тогда, вероятно, будет 3 vtables, по одному для каждого класса, но эти 3 vtables будут указывать на одну и ту же копию f() , поскольку в этом коде нет переопределенной копии.

2. Компилятор может делать все, что захочет. Может быть ноль v-таблиц, если у компилятора есть лучший способ сделать это.

3. Это определено реализацией. Ни одна из них не похожа на ваш пример, поскольку вы не переопределяете виртуальный метод.

Ответ №1:

Сколько виртуальных таблиц создается для следующего кода?

Язык C не определяет такую вещь, как виртуальная таблица. Это способ реализовать виртуальную отправку. Поскольку это деталь реализации, количество виртуальных таблиц также не определяется языком, и решение зависит от языковой реализации.

Таким образом, ответа нет, если вопрос не ограничен какой-либо конкретной языковой реализацией. Используя пример языковой реализации, для каждого из этих классов была создана виртуальная таблица:

 std::exception
std::bad_exception
std::type_info
std::bad_cast
std::bad_typeid
std::bad_alloc
std::bad_array_new_length
std::nested_exception
__cxxabiv1::__forced_unwind
std::locale::facet
std::__cxx11::collate<char>
std::__cxx11::collate<wchar_t>
std::__cxx11::collate_byname<char>
std::__cxx11::collate_byname<wchar_t>
std::logic_error
std::domain_error
std::invalid_argument
std::length_error
std::out_of_range
std::runtime_error
std::range_error
std::overflow_error
std::underflow_error
std::_V2::error_category
std::system_error
std::ios_base::failure
std::ios_base
std::basic_streambuf<char>
std::basic_streambuf<wchar_t>
std::ctype<char>
std::__ctype_abstract_base<wchar_t>
std::ctype<wchar_t>
std::ctype_byname<char>
std::ctype_byname<wchar_t>
std::__cxx11::numpunct<char>
std::__cxx11::numpunct<wchar_t>
std::__cxx11::numpunct_byname<char>
std::num_get<char>
std::num_put<char>
std::__cxx11::numpunct_byname<wchar_t>
std::num_get<wchar_t>
std::num_put<wchar_t>
std::basic_ios<char>
std::basic_ios<wchar_t>
std::basic_ostream<char>
std::basic_ostream<wchar_t>
std::basic_istream<char>
std::basic_istream<wchar_t>
std::basic_iostream<char>
std::basic_iostream<wchar_t>
A
B
C
  

Вот команда, которую я использовал для создания списка:

 g   -fdump-lang-class -std=c  17 main.cpp 
    amp;amp; grep Vtable main.cpp.*.class 
     | cut -f 3 -d ' '
  

Ответ №2:

Ответ — 3 виртуальные таблицы. Вы создали здесь 3 класса, так что это означает, что в этом коде будет 3 виртуальные таблицы.

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

1. Почему не может быть только одной виртуальной таблицы?

2. @user975989 потому что существует 3 разных класса. Пользовательский код может создать любую из них в любое время. И компилятор должен иметь возможность разыменовывать указатель на любую из них, чтобы получить доступ к допустимой виртуальной таблице. Таким образом, должно быть 3 отдельных vtables.

3. @RemyLebeau — И любой из этих объектов можно заставить указывать только на одну виртуальную таблицу. Будут вызываться те же самые точные функции. «Но как насчет RTTI», — скорее всего, скажете вы. Ну, это не используется в примере кода. Компилятор может доказать, что одной виртуальной таблице может не потребоваться информация RTTI, и поэтому ее можно использовать повторно (этому также могут помочь флаги компилятора). Вот почему эти вопросы (и попытки ответить на них) являются спорными, когда их задают в самом общем виде.