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

У меня были некоторые мысли о нескольких виртуальных деструкторах, особенно. после прочтения чтения 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;
}

это будет работать, как я и предполагал, без утечек памяти?

6

Решение

Прежде всего, если вы сделаете деструктор базового класса 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 по умолчанию это просто означает, что размер объекта всегда увеличивается на размер слова, что в целом неприемлемо.

4

Другие решения

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 будут удалены в обоих из них.

4

По вопросам рекламы [email protected]