Как создать конкретный класс из шаблонного класса
Скажем, у меня есть шаблон класса:
template <typename T> class StringDeque:
public std::deque<T>
{
public:
...
private:
typedef std::deque<T> BaseClass;
};
Скажи, я хочу создать конкретный класс ArrayString
где T=std::string
, Как правильно добиться этого:
определять
#define ArrayString StringDeque<string>
ЬурейеЕ
typedef StringDeque < string > ArrayString;
наследование
class ArrayString :
public StringDeque < string > {};
Я не уверен, что все предложения действительны. Во всяком случае, я пытаюсь выяснить, какая практика больше всего подходит.
3 ответа
Правильные способы:
typedef std::deque<std::string> StringDeque;
using StringDeque = std::deque<string>;
Тем не менее, вот еще несколько замечаний по вашему вопросу:
Вы написали:
template <typename T> class StringDeque: public std::deque<T> // ...
std
Контейнерные классы не подразумеваются как базовые классы. Это означает, что они не должны наследоваться от (а наследование от них - UB).
Когда вы хотите использовать std
Функциональность контейнера в другом классе, ответ всегда должен быть инкапсуляции. Это означает, что правильный способ использовать функциональность std::queue в ваших классах:
template<typename T> class StringDequeue {
std::deque<T> storage;
public:
// add interface here that uses storage
};
Вы также предложили это:
#define ArrayString StringDeque<string>
Пожалуйста, никогда не используйте define для объявления типа. Это работает, но имеет свои подводные камни и считается плохой практикой в C++.
Вы хотите дать имя определенному типу (который является экземпляром шаблона). C++ способ давать имена (псевдонимы) типам с помощью typedef:
typedef StringDeque<string> ArrayString;
Или, начиная с C++11, с объявлением псевдонима:
using ArrayString = StringDeque<string>;
Примечание: когда вы думаете об этом, это, как правило, помогает думать с точки зрения правильной терминологии шаблона. У вас нет "шаблона класса" (класс со специальными свойствами), у вас есть "шаблон класса" (шаблон для создания классов). Шаблон не является типом; его экземпляры есть.
Создать псевдонимы типа с typedef
или (начиная с C++ 11) using
:
typedef StringDeque<std::string> ArrayString;
using ArrayString = StringDeque<std::string>;
Препроцессор является кувалдой: иногда полезен, но, не зная конструкций языкового уровня, склонен удивительным образом нарушать код. В этом случае, я думаю, единственная проблема заключается в том, что имя не будет ограничено какой-либо областью; но это достаточная причина, чтобы этого избежать.
Наследование создает новый тип; хотя обычно его можно использовать там, где находится базовый тип, он не является полностью взаимозаменяемым и не наследует конструкторы от базового типа. Так что это также не то, что вы хотите для псевдонима простого типа.