2015-05-22 3 views
3

Существует this question на stackoverflow, который защищает правило Скотта Мейерса только за создание деструктора виртуального, если в этом классе есть виртуальные функции.Должен ли деструктор быть виртуальным, когда класс является частью более крупной структуры?

Я работаю в компании с большой каркасной платформой, и неясно время кодирования, если ваш класс может быть расширен в будущем. В этот момент также может быть невозможно изменить этот класс (поскольку он является частью выпущенного пакета).

Теперь представьте себе следующий сценарий:

class A { 
public: 
    A(); 
    virtual ~A(); 
    virtual m(); 
}; 

class B : public A { 
public: 
    B(); 
    ~B(); 
}; 

class C : public B { 
public: 
    C(); 
    virtual ~C(); 
    virtual m(); 
}; 

Так что я создал class B и сейчас, он не может быть изменен. Теперь class C создается и используется в качестве B:

B * b = new C(); 
delete b; 

Что будет происходить в том, что деструктор C никогда не называется, не так ли?

В этом сценарии: Если класс всегда есть виртуальный деструктор?

+0

Настоящий ответ - не злоупотреблять наследованием для расширения классов. Вместо этого используйте композицию. – nwp

+0

С устаревшим кодом использование наследования часто является единственным способом исправить ошибки или поведение. Например, мой код будет использоваться повторно без возможности его изменения. – Pascal

ответ

3

как ответ государств @Konrad Гроховски, в деструктор B является неявно виртуальным, поэтому поведение определено корректно. В вашем примере C::~C()будет вызываться. Из спецификации C++ § 12.4.8:

Деструктор может быть объявлен виртуальным (10.3) или чистым виртуальным (10.4); если в программе созданы какие-либо объекты этого класса или любого производного класса, деструктор должен быть определен. Если класс имеет базовый класс с виртуальным деструктором, его деструктор (независимо от того, объявлен ли пользователь или неявно) является виртуальным.

Более подходящий вопрос - это то, что происходит, когда базовый класс фреймворка фактически имеет не виртуальный деструктор (который, как я думаю, вы путешествуете), и ваш пользователь получает от него. Например:

// Your framework: 
class A 
{ 
public: 
    A(); 
    ~A(); // non-virtual 
}; 

// User's class: 
class B : public A 
{ 
    B(); 
    virtual ~B(); // virtual 
    virtual void UserMethod(); 
}; 

Как обсуждалось в этом вопросе (Non virtual destructor in base class, but virtual destructor in derived class cause segmentation fault), это может привести к пользователям столкнуться с проблемами. Если вы не знаете, будет ли пользователь выводиться из вашего класса, он должен иметь виртуальный деструктор, иначе есть проблемы.

Чтобы обеспечить надлежащее поведение с помощью не виртуальных деструкторов, вы можете запретить пользователю извлекать из класса, и в этом случае не виртуальный деструктор может быть безопасным, если вы правильно используете класс в своей структуре. В C++ 11 вы можете использовать final, чтобы запретить вывод. В C++ 03 и ниже вы можете использовать трюк here, чтобы запретить вывод.

+0

У нас было много случаев, когда в коде были ошибки (или нежелательное поведение), которые нельзя было изменить. Иногда мы получаем такие ошибки на более высоком уровне, исходя из них. В таком сценарии довольно плохо, если деструктор не является виртуальным. Конечно, авторы этого кода имели лучшие намерения, но не могли предвидеть среду, в которой их код будет запущен. – Pascal

+1

В C++ 11 вам не нужны трюки, чтобы запретить вывод, его можно выразить как «final class A { ...}; '. – nwp

+0

@nwp Обновленный ответ, спасибо. Я застрял в C++ 98 land :). – MuertoExcobito

9

, когда базовый класс имеет виртуальный деструктор, все классы, наследующие от него автоматически виртуального деструктора (так в вашем примере - деструктор B является неявным виртуальным)

если класс предназначен быть продлен/унаследованный он должен иметь виртуальный деструктор ,

0

Скотт Мейерс в своей книге «Эффективный C++: 55 конкретных способов улучшения ваших программ и дизайнов (3-е издание)» говорит, что деструктор должен быть объявлен virtual, если класс имеет другую виртуальную функцию. В противном случае будет создан только virtual destructor v-table, что вызовет некоторое дополнительное потребление ресурсов.

✦Polymorphic base classes should declare virtual destructors. If a 
class has any virtual functions, it should have a virtual destructor. 
✦Classes not designed to be base classes or not designed to be used 
polymorphically should not declare virtual destructors. 
Смежные вопросы