Защита деструкторов в абстрактном базовом классе не наследуется в C++?

Я обнаружил утечку памяти в моем коде, вызванную вызовом только деструктора базового класса для объектов. Эта проблема понята: я уже добавил virtual деструктору класса интерфейса MyÌnterface, Меня озадачивает то, что компилятор явно создал стандартный деструктор для моего вспомогательного класса MyHelperэто в конечном итоге называется. Я попробовал это с двумя разными компиляторами.

Это меня очень удивило, так как я заметил, что большинство реализаций по умолчанию не создаются, если члены или базовые классы вводят ограничения. Почему защита деструктора не передается по наследству?

#include <iostream>

class MyInterface
{
public:
    virtual void doSomethingUseful()=0;
    // a lot more functions declared omitted
    virtual void doSomethingElse()=0;
    virtual void doSomethingIndividual()=0;
protected:
    /// protected destructor to forbid calling it on interfaces
    ~MyInterface() {} // HERE the virtual is clearly missing
};

/// a common base that defaults most functions implementations
class MyHelper: public MyInterface
{
public:
    void doSomethingUseful() {}
    // a lot more default implementations omitted
    void doSomethingElse() {}
};

class SomeImplementation: public MyHelper
{
public:
    SomeImplementation()
    {
        std::cout << "SomeImplementation ctr" << std::endl;
    }
    ~SomeImplementation()
    {
        std::cout << "SomeImplementation dtr" << std::endl;
    }
    void doSomethingIndividual()
    {
        std::cout << "SomeImplementation did it." << std::endl;
    }
};

/// user of MyInterface cannot delete object mi passed as parameter
int deleteSafeUsage(MyInterface& mi)
{
    mi.doSomethingIndividual();
    // would cause a compiler error: delete &mi;
}

/// usage restricted to MyHelper level, only exception is object creation
int testIt()
{
    MyHelper* h = new SomeImplementation;
    deleteSafeUsage(*h);
    delete h; // <- HERE the memory leak happens!
}

Вот вывод приведенного выше примера кода, который "показывает" недостающие SomeImplementation ctr:

SomeImplementation ctr
SomeImplementation did it.

1 ответ

Решение

Конструкторы и деструкторы не наследуются. Так почему же их видимость наследуется?

Вы можете проверить стандарт, чтобы быть уверенным, но cppreference говорит об этом, акцент мой:

Если для типа класса (struct, class или union) не предусмотрен пользовательский деструктор, компилятор всегда объявляет деструктор как встроенный открытый член своего класса.

Итак, если вы хотите ~MyHelper Чтобы быть защищенным, вы должны объявить это явно.

Обратите внимание, что если MyInterface был виртуальный деструктор, неявный деструктор MyHelper также будет виртуальным. Так что этот аспект унаследован, в некотором роде. Опять же, вы хотите обратиться к стандарту, если хотите быть уверенным, но это упоминается в C++ faq lite

Для полноты, вот руководство Херба Саттерса о том, как использовать виртуальность в целом и с деструкторами.

Другие вопросы по тегам