Деструктор

  • Деструктор полиморфных классов должен быть виртуальным. Это же правило касается описания интерфейсов (как правило, чисто абстрактных классов). Это необходимо для корректного удаления экземпляра класса через указатель на его базовый класс.
  • Неполиморфные классы либо должны объявляться как final, либо деструктор в таких классах должен располагаться в protected области видимости (чтобы его мог вызвать деструктор дочернего класса), либо класс не должен иметь состояний (stateless) и к нему применяется оптимизация EBCO.

Пример:

class X {
public:
    ~X(); // Плохо! деструктор не виртуальный
    // публичные функции
private:
    // члены класса
}

class Y : public X {
public:
    ~Y();
    // публичные функции
private:
    // члены класса
}

int main() {
    std::unique_ptr<X> x = std::make_unique<Y>();
    return 0;
}

Если вы уверены, что от вашего класса наследоваться не должны, указывайте явно final:

class X final {
public:
    ~X(); // OK!
    // публичные функции
private:
    // члены класса
}

int main() {
    auto x = std::make_unique<X>();
    return 0;
}

Если вы хотите запретить удалять класс через указатель на базовый, поместите деструктор в protected область в базовом классе:

class X {
public:
    // публичные функции
protected:
    ~X(); // Ok!
private:
    // члены класса
}

class Y : public X {
public:
    ~Y();
    // публичные функции
private:
    // члены класса
}

int main() {
    auto x = std::make_unique<Y>();
    return 0;
}