если vtable создается во время компиляции, почему эта ошибка является ошибкой компоновщика, а не ошибкой компиляции?

Следующий фрагмент кода дает мне ошибку

неопределенная ссылка на `vtable for Derived'

Код :

#include <iostream>
class base{
    public:
    base(){}
    virtual ~base(){}
    virtual void test()
    {
    }
};
class Derived:public base{
    public:
    Derived(){}
    ~Derived(){}  
    void test();
};
int main() {
    base* b = new Derived ();
    delete b;
}

как я понимаю, это связано с тем, что виртуальная функция test объявлена, но не определена в class Derived.

Но когда я компилирую с g++ -c file.cpp в соответствии с этим C скомпилируйте или соберите исходные файлы, но не связывайте. Он не дает мне никаких ошибок и компилируется нормально. Следовательно, указанная выше ошибка генерируется во время связывания, а не во время компиляции. Из того, что я узнал, не было создано vtable во время компиляции. Тогда почему я не получаю ошибку во время компиляции?


person Hummingbird    schedule 19.11.2016    source источник
comment
Ошибка исходит от компоновщика, как показала бы вам минутная проверка.   -  person user207421    schedule 19.11.2016
comment
@EJP да, я понимаю это и упомянул то же самое в самом вопросе. но чего я не понимаю, так это того, что я не должен получать его во время компиляции, а не связывать.   -  person Hummingbird    schedule 19.11.2016
comment
описание во время компиляции включает время компоновки, но не время выполнения   -  person M.M    schedule 19.11.2016
comment
при компиляции file.cpp ошибки нет, потому что виртуальная таблица может быть найдена в другом блоке, и только когда вы доберетесь до компоновки, компоновщик увидит, что ее нет ни в одном блоке.   -  person M.M    schedule 19.11.2016


Ответы (4)


Однако вы сформировали представление о том, что vtable должна быть создана во время компиляции, вы ошибаетесь.

Раздельная компиляция является основной концепцией стандарта. Это причина того, что модуль компиляции (также известный как исходный файл) может скомпилироваться при любом объявлении функции, в которой он нуждается, даже если он не имеет видимости определения.

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

Затем компоновщик должен обнаружить отсутствие определения функции.

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

person Peter    schedule 19.11.2016
comment
Спасибо .. теперь я думаю, что понимаю это ... и для части vtable я взял ссылку из здесь - person Hummingbird; 19.11.2016
comment
Эта ссылка просто говорит, что создание vtable обрабатывается реализацией. Это не говорит, что это происходит исключительно во время компиляции. В цепочке инструментов компиляции, а затем компоновки компоновщик является компонентом реализации. - person Peter; 19.11.2016
comment
Я согласен с вами и понимаю вашу точку зрения ... хотя в ссылке действительно говорится, что цитирование vtables - это структуры, созданные во время компиляции , что меня смутило. - person Hummingbird; 19.11.2016
comment
Да, хорошо. Существует разница между указанием виртуальной таблицы (например, ее макета) и ее заполнением. Ответ в этой ссылке использует слово created, когда, вероятно, следует использовать формулировку, указывающую макет. - person Peter; 19.11.2016
comment
Так что просто для лучшего понимания... макет виртуальных таблиц указывается во время компиляции, но заполняется во время компоновки... правильно ли я понимаю? .. следовательно, полная компиляция, а затем цепочка ссылок имеет значение. правильно? - person Hummingbird; 19.11.2016
comment
Детали варьируются в зависимости от разных наборов инструментов, но в целом этого достаточно. - person Peter; 19.11.2016

Компилятор не требует наличия всех доступных методов. Ему достаточно их декларации.

Этот метод может быть реализован в другой единице компиляции (файл cpp/cxx), поэтому для компилятора даже невозможно проверить, доступен ли этот метод где-то еще. Компилятор обрабатывает один файл cpp за раз.

Задача компоновщика — сопоставить методы и вызовы вместе.

person woockashek    schedule 19.11.2016

Что я получаю с g++ foo.cpp -v

/tmp/ccBc4VPu.o: In function `Derived::Derived()':
foo.cpp:(.text._ZN7DerivedC2Ev[_ZN7DerivedC5Ev]+0x1f): undefined reference to `vtable for Derived'
collect2: error: ld returned 1 exit status

Это ошибка компоновщика, а не ошибка компилятора как таковая.

Основная причина ошибки в том, что test объявлен в Derived, но фактически не реализован. Компоновщик выдает запутанное сообщение об ошибке. Он должен объявлять об ошибке для отсутствующего метода Derived::test

person selbie    schedule 19.11.2016
comment
это точный вопрос, почему это ошибка компоновщика? из чего я узнал, что vtables были созданы во время компиляции? поэтому было бы здорово узнать, почему я не получаю ошибку также во время компиляции, а не во время компоновки. - person Hummingbird; 19.11.2016

В GCC есть часто задаваемые вопросы по этой проблеме:

При сборке C++ компоновщик говорит, что мои конструкторы, деструкторы или виртуальные таблицы не определены, но я их определил

Решение состоит в том, чтобы гарантировать, что все виртуальные методы, которые не являются чистыми, определены. Обратите внимание, что деструктор должен быть определен, даже если он объявлен чисто виртуальным [class.dtor]/7.

person Nikita    schedule 19.11.2016
comment
Спасибо, я понимаю это, но чего я не могу понять, так это того, что если vtable создается во время компиляции, то почему я не получаю ошибку только во время компиляции, а скорее получаю во время компоновки ... если это не слишком много, чтобы спросить. - person Hummingbird; 19.11.2016
comment
@DevanshMohanKaushik vtable выделяется компилятором и инициализируется компоновщиком. Похоже, Питерс описал это подробно. - person Nikita; 19.11.2016
comment
да, это то, что я был смущен .. Спасибо в любом случае - person Hummingbird; 19.11.2016