Листинг 19.2. Использвание шаблона массива
1: #include
2:
3: const int DefaultSize = 10;
4:
5: // обычный класс Animal для
6: // создания массива животных
7:
8: class Animal
9: {
10: public:
11: Animal(int);
12: Animal();
13: ~Animal() { }
14: int GetWeight() const { return itsWeight; }
15: void Display() const { cout << itsWeight; }
16: private:
17: int itsWeight;
18: };
19:
20: Animal::Animal(int weight):
21: itsWeight(weight)
22: { }
23:
24: Animal::Animal():
25: itsWeight(0)
26: { }
27:
28:
29: template // обьявляем шаблон и параметр
30: class Array // параметризованный класс
31: {
32: public:
33: // конструкторы
34: Array(int itsSize - DefaultSize);
35: Array(const Array &rhs);
36: ~Array() { delete [] pType; }
37:
38: // операторы
39: Array& operator=(const Array&);
40: T& operator[](int offSet) { return pType[offSet]; }
41: const T& operator[](int offSet) const
42: { return pType[offSet]; }
43: // методы доступа
44: int GetSize() const { return itsSize; }
45:
46: private:
47: T *рТуре;
48: int itsSize;
49: };
50:
51: // выполнения...
52:
53: // выполняем конструктор
54: template
55: Array::Array(int size):
56: itsSize(size)
57: {
58: pType = new T[size];
59: for (int i = 0; i
60: pType[i] = 0;
61: }
62:
63: // конструктор-копировщик
64: template
65: Array::Array(const Array &rhs)
66: {
67: itsSize = rhs.GetSize();
68: pType = new T[itsSize];
69: for (int i = 0; i
70: pType[i] = rhs[i];
71: }
72:
73: // оператор присваивания
74: template
75: Array& Array::operator=(const Array &rhs)
76: {
77: if (this == &rhs)
78: return *this;
79: delete [] pType;
80: itsSize = rhs.GetSize();
81: pType = new T[itsSize];
82: for (int i = 0; i
83: pType[i] = rhs[i];
84: return *this;
85: }
86:
87: // исполняемая программа
88: int main()
89: {
90: Array theArray; // массив целых
91: Array theZoo; // массив животных
92: Animal *pAnimal;
93:
94: // заполняем массивы
95: for (int i = 0; i < theArray.GetSize(); i++)
96: {
97: theArray[i] = i*2;
98: pAnimal = new Animal(i*3);
99: theZoo[i] = *pAnimal;
100: delete pAnimal;
101: }
102: // выводим на печать содержимое массивов
103: for (int j = 0; j < theArray.GetSize(); j++)
104: {
105: cout << "theArray[" << j << "]:\t";
106: cout << theArray[j] << "\t\t";
107: cout << "theZoo[" << j << "]:\t";
108: theZoo[j].Display();
109: cout << endl;
110: }
111:
112: return 0;
113: }
Результат:
theArray[0] 0 theZoo[0] 0
theArray[1] 2 theZoo[1] 3
theArray[2] 4 theZoo[2] - 6
theArray[3] 6 theZoo[3] 9
theArray[4] 8 theZoo[4] 12
theArray[5] 10 theZoo[5] 15
theArray[6] 12 theZoo[6] 18
theArray[7] 14 theZoo[7] 21
theArray[8] 16 theZoo[8] 24
theArray[9] 18 theZoo[9] 27
Анализ:В строках 8-26 выполняется создание класса Animal, благодаря которому объекты определяемого пользователем типа можно будет добавлять в массив.
Содержимое строки 29 означает, что в следующих за ней строках объявляется шаблон, параметром для которого является тип, обозначенный идентификатором Т. Класс Array содержит два конструктора, причем первый конструктор принимает размер и по умолчанию устанавливает его равным значению целочисленной константы DefaultSize.
Затем объявляются операторы присваивания и индексирования, причем объявляются константная и не константная версии оператора индексирования. В качестве единственного метода доступа служит функция GetSize(), которая возвращает размер массива.
Можно, конечно, представить себе и более полный интерфейс. Ведь для любой серьезной программы создания массива представленный здесь вариант будет недостаточным. Как минимум, пришлось бы добавить операторы, предназначенные для удаления элементов, для распаковки и упаковки массива и т.д. Все это предусмотрено классами контейнеров библиотеки STL, но к этому мы вернемся в конце занятия.
Раздел закрытых данных содержит переменные-члены размера массива и указатель на массив объектов, реально помещенных в память.
Если вы хотите передать функции объект массива, нужно передавать конкретный экземпляр массива, а не шаблон. Поэтому, если некоторая функция SomeFunction() принимает в качестве параметра целочисленный массив, используйте следующую запись:
void SomeFunction(Array&); // правильно
А запись
void SomeFunction(Array&); // ошибка!
неверна, поскольку отсюда не ясно, что представляет собой выражение T&. Запись
void SomeFunction(Array &); // ошибка!
тоже ошибочна, так как объекта класса Array не существует — есть только шаблон и его экземпляры.
Чтобы реализовать более общий подход использования объектов, созданных на основе шаблона, нужно объявить функцию шаблона:
template
void MyTemplateFunction(Array&); // верно
Здесь MyTemplateFunction() объявлена как функция шаблона, на что указывает первая строка объявления. Заметьте, что функции шаблонов, подобно другим функциям, могут иметь любые имена.
Функции шаблонов, помимо объектов, заданных в параметризованной форме, могут также принимать и экземпляры шаблона. Проиллюстрируем это на примере:
template
void MyOtherFunction(Array&, Array&); // верно
Читать дальше