Завдання 18, останнє з 20 січня

в
  1. Чи можна мати не віртуальний деструктор у класі, якщо один з методів абстрактний?
  2. Як спрацює поліморфний виклик через this в базовому класі:
    • У конструкторі.
    • У віртуальному деструкторі.
    • У звичайному деструкторі.
  3. Чи можна унаслідувати конструктор базового класу?
  4. В яких випадках визначають абстрактний член класу (деструктор, метод)?

1. Чи можна мати не віртуальний деструктор у класі, якщо один з методів абстрактний?

Так, синтаксично це не є помилкою, проте абстрактний метод вказує на використання поліморфізму. Якщо хоча б один з класів має (чи в майбутньому матиме) нетривіальний деструктор, то він ніколи не викликатиметься. Щоб уникнути подібних логічних помилок в програмі, правило просте: якщо хоча б один метод віртуальний, то деструктор базового класу також має бути віртуальним.

2. Як спрацює поліморфний виклик через this в базовому класі:

  • В конструкторі.
  • В віртуальному деструкторі.
  • В звичайному деструкторі.




В деструкторі, незалежно від того віртуальний він чи ні, поліморфізм працює без ніяких особливостей.
В конструкторі поліморфізм через this не працює, бо при виклику конструктора класу-предка об'єкт класу-нащадка ще не існує. Через це завжди викликатиметься метод класу, який конструюється в даний момент (метод класу-предка). Наступний код, де базовий клас викликає віртуальний метод в конструкторі, двічі виведе Base, а не Base і Derived:
#include <iostream>

struct Base {
   Base() { this->print();}

   virtual void print() { std::cout << "Base" << std::endl; }
};

struct Derived : public Base {
   virtual void print() { std::cout << "Derived" << std::endl; }
};

int main() {
   Base* base;
   base = new Base(); delete base;
   base = new Derived(); delete base;
   return 0;
}

3. Чи можна унаслідувати конструктор базового класу?





Так, конструктори в C++ не наслідуються за замовчуванням, але їх можна наслідувати явно за допомогою директиви using:
struct Base {
   Base(int a, int b) {}
};

struct Derived : public Base {
   using Base::Base;
};
Виклик конструктора з параметрами, наприклад, Derived(1, 2), буде синтаксично коректним в такому випадку. Без using, такого конструктора в Derived не буде і виникне помилка на етапі компіляції.

4. В яких випадках визначають абстрактний член класу (деструктор, метод)?





Абстрактний деструктор визначають завжди. Якщо його не визначити, але в коді використовувати об'єктів класів-нащадків, то він викликатиметься неявно. Через це виникне помилка на етапі лінкування, що деструктор базового класу оголошений, але не має визначення ("undefined reference").
Абстрактний метод визначають, якщо він має явно викликатись у класі-нащадку:
struct Base {
   virtual void print() = 0;
};

void Base::print() { std::cout << "Base" << std::endl; }

struct Derived : public Base {
   virtual void print() { this->Base::print(); }
};

Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Максимальный размер загружаемого файла: 1 ГБ. Вы можете загрузить: изображение, аудио, видео, документ, таблица, интерактив, текст, архив, код, другое. Ссылки на YouTube, Facebook, Twitter и другие сервисы, вставленные в текст комментария, будут автоматически встроены. Перетащите файл сюда