Ответ на ваш первый вопрос,
Что вызывает нерешенное внешнее в
компоновщик, когда .dtor является виртуальным
или когда .ctor не встроен?
... просто у вас нет определения деструктора.
Теперь ваш второй вопрос несколько интереснее:
почему я не получаю неразрешенного
внешний, если я сделаю деструктор
не виртуальный, или если я в строке
конструктор?
И причина в том, что вашему компилятору не нужен деструктор X
, так как вы никогда не создавали экземпляр X
, поэтому он отбросил весь ваш класс. Если вы попытаетесь скомпилировать эту программу, вы получите неразрешенное внешнее:
class X
{
public:
X();
~X();
};
X::X() {};
int main()
{
X x;
return 0;
}
Но если вы закомментируете X x;
, то, как вы заметили, он будет компилироваться просто отлично.
Теперь давайте вернемся к тому, почему он не скомпилируется, если деструктор, если virtual
. Я размышляю здесь, но я полагаю, что причина в том, что, поскольку у вас есть виртуальный деструктор, X
теперь является полиморфным классом. Чтобы разложить полиморфные классы в памяти, компиляторам, которые реализуют полиморфизм с использованием vtable , нужны адреса для каждой виртуальной функции. Вы не внедрили X::~X
, поэтому нерешенные внешние результаты.
Почему компилятор просто не выбрасывает X
, как это было, когда X
не был полиморфным классом? Больше предположений здесь. Но я ожидаю, что причина в том, что даже если вы непосредственно не создали экземпляр X
, нельзя быть уверенным, что нигде в вашем коде не будет X
live, маскирующегося под нечто иное. Для примера рассмотрим абстрактный базовый класс. В этом случае вы никогда не создадите экземпляр Base
напрямую, а код для Derived
может быть в полностью отдельной единице перевода. Поэтому, когда компилятор попадает в этот полиморфный класс, он не может отбросить его, даже если не знает, что вы его создали.