Здравствуйте, Muxa, Вы писали:
M>Представьте себе иерархию классов.
M>Разработчик самого базового из них не сделал деструктор виртуальным.
M>Для чего он мог это сделать?
Реализовать гибкую стратегию владения объектами можно и без виртуальных деструкторов. Приведу пример. Я определяю некий абстракный интерфейс, состоящий полностью из чисто виртуальных функций:
class IFoo
{
public:
virtual void bar() = 0;
virtual void baz() = 0;
protected:
IFoo() { }
};
Причем деструктор этого абстрактного класса я намеренно объявляю невиртуальным и защищенным, тем самым как бы подчеркивая, что стратегия владения объектами выбирается разработчиком производных классов. При этом у разработчика производного класса есть две возможности: 1) (традиционный) сделать деструктор производного класса открытым и виртуальным; 2) сделать деструктор невиртуальным и защищенным, а для создания объектов реализовать фабричный метод.
Пример второго варианта:
using boost::shared_ptr;
class FooDerived1 : public IFoo
{
public:
virtual void bar();
virtual void baz();
static shared_ptr<FooDerived1> create_instance(/*possible arguments*/);
{
return shared_ptr<FooDerived1>(new FooDerived(/*possible arguments*/));
}
protected:
FooDerived1();
};
class FooDerived2 : public IFoo { /*...*/ };
class FooDerived3 : public IFoo { /*...*/ };
А вот теперь замечательный момент: умный указатель производного типа, возвращаемый фабричным методом
create_instance, легко преобразуется в умный указатель абстрактного типа. Это позволяет владеть объектами и корректно удалять их полиморфно:
int main()
{
typedef std::vector<boost::shared_ptr<IFoo> > Items;
Items items;
items.push_back(FooDerived1::create_instance(/*possible arguments*/));
items.push_back(FooDerived2::create_instance(/*possible arguments*/));
items.push_back(FooDerived3::create_instance(/*possible arguments*/));
//...
}
Преимущество такого подхода: отделение основной функциональности абстрактных классов от способов владения конкретными объектами. Т.о. в прикладной программе точка создания объектов как бы изолирована от использования этих объектов. Это улучшает структурированность кода, тестируемость и пр. и др.