У меня были некоторые мысли о нескольких виртуальных деструкторах, особенно. после прочтения чтения http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx .
Предположим, у меня есть
class Base
{
public:
Base();
virtual ~Base();
private:
Logger* _logger;
};
//and
class Derived : public Base{
public:
Derived();
virtual ~Derived();
private:
Logger* _logger;
};
в файлах cpp, в каждом деструкторе я удаляю соответствующий _logger
указатели
Base::~Base(){ //base.cpp
delete _logger;
}
Derived::~Derived(){ //derived.cpp
delete _logger;
}
это будет работать, как я и предполагал, без утечек памяти?
Прежде всего, если вы сделаете деструктор базового класса virtual
все производные классы автоматически получат virtual
деструктор, если вы объявите их как virtual
или нет. Это обычно верно для сопоставления подписей: если базовый класс имеет virtual
функция с той же сигнатурой, что и функция в производном классе, функция в производном классе override
и является virtual
(хотя в C ++ 2011 вы можете предотвратить дальнейшее переопределение, используя final
ключевое слово, в этом случае другое переопределение приведет к ошибке).
Тем не менее, деструкторы особенные: когда вы делаете деструктор virtual
он все равно будет вызываться, даже если есть другой главный деструктор! Единственное воздействие деструктора virtual
это то, что происходит, если вы delete
объект, использующий указатель на базовый класс, когда объект фактически имеет производный тип: если деструктор не virtual
вы получаете неопределенное поведение, в то время как правильное происходит, если деструктор virtual
, Например:
class not_a_base {};
class bad_idea: public not_a_base {};
class a_base { public: virtual ~a_base() {} };
class ok: public a_base {};
int main() {
a_base* ab = new ok;
delete ab; // <---- all is good here!
not_a_base* nab = new bad_idea;
delete nab; // <---- results in undefined behavior
}
Причина деструкторов не virtual
по умолчанию это просто означает, что размер объекта всегда увеличивается на размер слова, что в целом неприемлемо.
Base::_logger
это другая переменная, то Derived::_logger
, Так что вы должны удалить Derived::_logger
в деривере, а иначе у вас утечка памяти.
Обратите внимание, что это не имеет ничего общего с приватностью. Рассмотрим этот пример программы:
#include <iostream>
class A {
public:
bool foo;
};
class B: public A {
public:
bool foo;
};
int main()
{
B b;
std::cout << &b.B::foo << ' ' << &b.A::foo << '\n';
}
Адреса разные. Это означает, что это разные переменные, даже если они имеют одинаковые имена. Это возможно, так как каждый класс представляет свое собственное пространство имен, поэтому имена на самом деле не конфликтуют. Первый — A :: foo, другой — B :: foo.
Так как ваши деструкторы являются виртуальными, будут вызваны и правильные _logger
будут удалены в обоих из них.