Подтвердить что ты не робот

Деструкторы для классов интерфейса С++

Начиная использовать PC-Lint на существующей базе кода (страх и трепет).

Одна вещь, на которую он жалуется, следующая:

 class IBatch
 {
 public:
    virtual void StartBatch() =0;
    virtual int CommitBatch() =0;
 };

Что, когда другой класс вытекает из этого, чтобы использовать его как интерфейс

base class 'IBatch' has no destructor

Итак, вопрос: когда вы создаете классы интерфейса, подобные выше, вы всегда включаете виртуальный деструктор? Зачем? (это стиль или ошибка кодирования?)

EDIT: Должен был сказать, что я не ожидаю или не хочу, чтобы пользователь IBatch разрушал, они являются потребителем только сервиса, через этот интерфейс к некоторому внешнему классу реализации (если бы это имело бы значение)

4b9b3361

Ответ 2

Ошибка кодирования. Деструктор для вашего производного класса никогда не будет вызван, если вызван через указатель на базовый класс.

Когда вы реализуете IBatch и ссылаетесь на свой производный класс указателем на базовый класс (указатель на IBatch), и вы вызываете delete на этом указателе на базовый класс, вы можете потерять память, потому что деструктор для вашего производного класса никогда не будет вызван.

Основное правило: когда класс имеет хотя бы один метод virtual, он должен иметь деструктор virtual.

class IBatch
{
    public:
       virtual void f() = 0;
};

class A : public IBatch
{
    public:
       void f() {}
       ~A() {}
};

IBatch * a = new A();
a->f();    // calls A::f()
delete a;  // calls IBatch::~IBatch() not A::~A()

Ответ 3

Если есть виртуальные функции, должен быть виртуальный деструктор. Всегда. Не имеет значения, что это только класс интерфейса - ему все еще нужен виртуальный деструктор.

Либо это, либо ему нужен protected невиртуальный деструктор. Но тогда вы не можете удалить объект с помощью указателя интерфейса.

Ответ 4

Класс с виртуальными функциями, но не виртуальный деструктор, является подозрительным и, скорее всего, неправильным: см. хорошее и более точное объяснение здесь.

Ответ 5

Итак, вопрос: когда вы создаете Интерфейсные классы, подобные описанным выше, делают вы всегда включаете виртуальную деструктор? Зачем? (это стиль или ошибка кодирования?)

Ну, это действительно так. Если вы когда-либо вызываете delete на указателе IBatch, он, вероятно, не будет делать то, что вы ожидаете. Конечно, если у вас есть что-то вроде виртуального Init/Shutdowns или AddRef/Releases, то это не проблема.

Ответ 6

Компилятор ставит деструктор по умолчанию, который не является виртуальным, что подразумевает, что "удаление" на указателе на виртуальный базовый класс будет успешным с результирующей утечкой памяти. Таким образом, это ошибка реализации, ни стиль, ни ошибка кодирования.