Дизайн шаблона контейнера указателя - PullRequest
0 голосов
/ 22 сентября 2010

Я хотел бы написать «универсальный» класс, представляющий общий контейнер, хранящий указатели. Должен ли я использовать публичное наследование или сдерживание?

template <class T>
class List : public std::vector <T *>
{
//...
}

Или

template <class T>
class List
{
private:
   std::vector <T *> items;
//...
}

Могут ли возникнуть некоторые проблемы с абстрактными классами (то есть виртуальным деструктором)?

Если ни одно из предложений не подходит, какой дизайн мне следует использовать (и не могли бы вы привести краткий пример)?

Ответы [ 3 ]

3 голосов
/ 22 сентября 2010

Это уже сделано для вас с контейнерами-указателями Boost .

Мне не нравится boost, поэтому я хотел бы использовать только стандарт C ++ 0x00: -).
- Ян (комментарий)

Если вы все еще хотите заново изобрести эти классы, посмотрите на принятые ими дизайнерские решения.В частности, они не наследуются от других контейнеров, как ваш первый код.

Фактически, просто скопируйте код прямо из Boost.Это библиотека только для заголовков, и она должна быть простой (т. Е. Несколько обходных путей для конкретной реализации). Лицензия Boost очень либеральна, даже не требуя упоминания Boost при распространении скомпилированных программ.

2 голосов
/ 22 сентября 2010

Как насчет:

typedef std::vector<boost::shared_ptr<T> > List;

То есть, я думаю, что лучше использовать указатель управления ресурсами в обычных классах контейнеров, чем заново изобретать каждый из классов контейнеров, чтобы добавить возможность управления ресурсами.

0 голосов
/ 22 сентября 2010

private наследование является распространенной тактикой для создания классов, которые реализуются в терминах другого.Код, использующий класс, не может сказать, что производный класс является производным от частной базы, поэтому вы не попадете в ситуации, когда обычно требуется виртуальный деструктор.

Использование usingимпортировать членов из частной базы в производный класс.Например:

template<class T>
class List:
private std::vector<T>
{
public:
    using std::vector<T>::operator[];
    using std::vector<T>::size;
};

Это немного грубо, но дает вам некоторую гибкость.Вы можете начать с использования частного наследования, и это сэкономит вам некоторую типизацию по сравнению с написанием функций пересылки, но вы по-прежнему можете писать альтернативные реализации длинным способом, как требуется.И затем, если / когда это становится неуместным, вы можете изменить стиль реализации - возможно, иметь vector в качестве члена, например, или, возможно, сделать все вручную - безопасно, зная, что клиентскому коду не понадобитсяизменить.

Это идеально подходит для ситуаций, когда вы уверены, что в конечном итоге вам понадобится контейнер нестандартного типа, но у вас есть существующий тип контейнера, который в настоящее время в основном соответствует требованиям.И это лучшее среднесрочное решение, чем typedef, потому что нет риска случайного (или умышленного) использования клиентского кода двумя этими типами взаимозаменяемо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...