Кто-нибудь знает, почему контейнеры STL не имеют виртуальных деструкторов?
Насколько я могу судить, единственными преимуществами являются:
- он уменьшает размер экземпляра одним указателем (к таблице виртуальных методов) и
- он делает разрушение и строительство немного быстрее.
Недостатком является то, что небезопасно подклассифицировать контейнеры обычным способом.
EDIT: Возможно, мой вопрос можно перефразировать: "Почему не были контейнеры STL, предназначенные для наследования?"
Поскольку они не поддерживают наследование, каждый из них придерживается следующих вариантов, когда требуется новый контейнер, для которого требуется функция STL, а также небольшое количество дополнительных функций (скажем, специализированный конструктор или новые аксессоры со значениями по умолчанию для карта или что-то еще):
- Репликация композиции и интерфейса: создайте новый шаблон или класс, который владеет контейнером STL в качестве частного члена, и имеет один сквозной встроенный метод для каждого метода STL. Это так же эффективно, как и наследование, позволяет избежать стоимости таблицы виртуальных методов (в тех случаях, когда это имеет значение). К сожалению, контейнеры STL имеют довольно широкие интерфейсы, поэтому для этого требуется много строк кода для чего-то, что должно быть легко сделать.
- Просто выполните функции: используйте голые (возможно, шаблонные) функции с файловыми областями вместо того, чтобы пытаться добавить функции-члены. В некотором смысле это может быть хорошим подходом, но преимущества инкапсуляции теряются.
- Состав с публичным доступом STL: пусть владелец контейнера STL позволяет пользователям напрямую обращаться к самому контейнеру STL (возможно, через аксессуры). Это требует наименьшего кодирования для библиотеки, но это гораздо менее удобно для пользователей. Одна из больших точек продажи композиции заключается в том, что вы уменьшаете сцепление в коде, но это решение полностью связывает контейнер STL с контейнером владельца (потому что владелец возвращает истинный контейнер STL).
- Полиморфизм времени компиляции: может быть несколько сложным для написания, требует некоторой программной гимнастики и не подходит для всех ситуаций.
В качестве побочного вопроса: существует ли безопасный способ подкласса с не виртуальными деструкторами (допустим, что я не хочу переопределять какие-либо методы, просто чтобы добавить новые)? Мое впечатление, что нет универсального и безопасного способа сделать это, если у вас нет возможности изменить код, определяющий не виртуальный класс.
ИЗМЕНИТЬ 2:
Как @doc указывает, объявления С++ 11 fancier using
несколько снижают стоимость композиции.