Си++: различия между версиями

Содержимое удалено Содержимое добавлено
Строка 502:
 
== Generic programming ==
 
=== Введение, или альтернативные подходы ===
 
Предположим, мы написали суперконтейнер (то есть тип, предназначенный для хранения) чисел типа <tt>int</tt>:
class IntContainer {
public:
void add (int value);
int index_of (int value);
int get_count ();
int get_value (int index);
private:
… … …
};
 
Однако нам грустно тратить силы, создавая суперконтейнеры для каждого типа данных, который мы собираемся использовать. Тем более, что их код будет похож, как две капли воды. Что же делать?
 
Есть старый приём, использовавшийся в Си. Он оригинален и неожидан, как и всё в Си. Применительно к нашей ситуации, он выглядит так (разумеется, в Си классов не было, и поэтому там всё выглядело иначе):
#define DEFINE_CONTAINER(T,N) \
class N ## Container { \
public: \
void add (T value); \
int index_of (T value); \
int get_count (); \
T get_value (int index); \
private: \
… … … \
};
 
Это — длинное определение макроса «<tt>DEFINE_CONTAINER</tt>». Оно занимает несколько строк благодаря использованию «символа продолжения макроса на следующую строку» — «<tt>\</tt>». Символы «<tt>##</tt>» используются, чтобы соединить вместе аргумент «<tt>N</tt>» и слово «<tt>Container</tt>», получив одно слово — название определяемого класса.
 
Используется это так:
DEFINE_CONTAINER (int, Int)
IntContainer apples;
void main () {
apples.add (11);
apples.add (13);
}
Строка «<tt>DEFINE_CONTAINER (int, Int)</tt>» раскрывается в определение класса «<tt>IntContainer</tt>», который мы и используем далее. Если нам понадобится контейнер для другого типа, мы можем написать «<tt>DEFINE_CONTAINER (double, Double)</tt>», «<tt>DEFINE_CONTAINER (const char *, ConstString)</tt>». Получатся классы «<tt>DoubleContainer</tt>» и «<tt>ConstStringContainer</tt>».
 
Можно обойтись и без макросов. Мы могли бы создать файлы «<tt>FooContainer._h_</tt>» и «<tt>FooContainer._cpp_</tt>». В их можно было определить контейнер «<tt>FooContainer</tt>» для типа «<tt>foo</tt>». Далее, вы используете ваш любимый текстовый редактор, чтобы скопировать их, например, в «<tt>IntContainer.h</tt>» и «<tt>IntContainer.cpp</tt>», заменив все вхождения слов «<tt>Foo</tt>» и «<tt>foo</tt>» на «<tt>Int</tt>» и «<tt>int</tt>» соответственно. Этот процесс можно автоматизировать. В нужный момент вы просто включите файл «<tt>IntContainer.h</tt>» и будете им пользоваться, как будто он написан вручную.
 
То, чем вы занимаетесь при любом из этих подходов, можно назвать словом «generic programming», или просто программирование шаблонов. (Вполне понятно, почему «<tt>DEFINE_CONTAINER</tt>» и «<tt>FooContainer._h_</tt>/<tt>._cpp_</tt>» можно назвать ''шаблонами'' контейнеров.)
 
Однако, в Си++ есть родной (встроенный) способ создавать шаблоны, без некрасивых макросов и неудобных манипуляций с файлами.
 
=== Шаблоны классов ===
Строка 516 ⟶ 560 :
 
=== Наследование и шаблоны ===
 
 
== Стандартная библиотека ==