У меня возникают проблемы с пониманием причины сбоя в следующем коде:
class A {
public:
virtual ~A() { goo(); }
void goo() { absFoo(); }
virtual void absFoo() = 0;
};
class B : public A {
public:
void absFoo() { cout << "In B \n"; }
};
int main()
{
B b1;
b1.goo();
}
Основное печатает «В B», как и ожидалось, но в конце, когда он падает, я тоже не могу его отладить, компилятор выдает странное сообщение.
Так что мой вопрос, когда деструктор A вызывает «goo ()», делает «absFoo ()», происходит сбой
потому что мы имеем в виду абстрактную функцию?
Или же действительно ли компилятор ищет определение в производных классах? (И он больше не существует, потому что он был разрушен заранее, поэтому он падает)
Я знаю, что если бы мы вызывали «absFoo ()» непосредственно из деструктора, причиной была бы абстрактная функция. Но так как здесь это внешняя функция, вызывающая «absFoo ()», у меня возникают проблемы с пониманием реальной причины.
Что происходит, когда деструктор вызывает абстрактную функцию
Во-первых, давайте рассмотрим, что происходит, когда деструктор вызывает любую виртуальную функцию (кстати, то же самое относится и к конструктору): когда виртуальная функция foo
называется в деструкторе T
вызов не будет динамически отправляться реализации в производном типе (время жизни любого производного объекта уже закончилось), но статически для реализации T::foo
,
Если T::foo
чисто виртуальный, то вызов его без динамической отправки будет иметь неопределенное поведение. Вот что происходит, когда чисто виртуальная функция (косвенно) вызывается в деструкторе (или конструкторе).
Просто чтобы дополнить уже принятый ответ, это документация от cppreference.
Когда виртуальная функция вызывается прямо или косвенно из
конструктор или от деструктора (в том числе во время строительства или
уничтожение нестатических элементов данных класса, например, в член
список инициализатора), и объект, к которому применяется вызов, является
объект находится в стадии строительства или уничтожения, вызываемая функция
последний переопределитель в классе конструктора или деструктора, а не один
переопределение в более производном классе.Другими словами, во время строительства или разрушения более производные классы не существуют.
Поскольку объект деконструирован, vtable обновляется, чтобы соответствовать новому статусу объекта.
Поскольку вы удалили последнюю функцию, компилятор сделает все, что сочтет нужным; что в случае отладочной компиляции в visual studio приведет к отказу в сообщении о том, что была вызвана чисто виртуальная функция.
Однако vtable не является частью стандарта, это детали реализации, и для вашей программы не требуется сбой; это то, что считается самым приятным, когда вы вызываете чисто виртуальную функцию.