C++ Программирование в среде С++ Builder 5

Разное


В этом параграфе мы расскажем о некоторых возможностях шаблонов, предусмотренных в стандартном C++, но не реализуемых компилятором C++Builder. Нам кажется, что о них необходимо рассказать, хотя бы для того, чтобы, читая другие книги по C++, вы не пытались осуществить в C++Builder методики, которые на нем осуществить невозможно.

В конце концов, C++Builder не является универсальным инструментом. Он ориентирован на визуальное программирование, а те моменты, о которых мы будем здесь говорить, второстепенны с этой, да и, пожалуй, с любой другой точки зрения.

Если у вас есть Borland C++ 5 или более поздняя версия, и вы хотя бы немного умеете с ним работать, то можете при желании разобрать с его помощью приведенные ниже примеры.

Специализация шаблона класса

Подобно шаблону функции, шаблон класса может быть специализирован для специфического набора его аргументов. Для этого нужно написать явные реализации тех или иных методов шаблона для конкретных типов. Вот, например, шаблон, который генерирует класс массива объектов, в том числе символьных строк, для которых отдельно реализуется функция добавления в массив и деструктор:

#include <iostream.h>

#include <string.h>

const int DefSize = 4;

template <class T> Glass MyArray { protected:

int size;



int current;

T *arr;

public:

MyArray (int n = DefSize) { size = n;

current = 0;

arr = new T[size];

}

~MyArray ();

void Insert(const T Sitem);

T &Get(int idx) { return arr[idx]; } };

// Общий шаблон Insert:

template <class T> void MyArray<T>::Insert(const T Sitem)

{

if (current == size) return;

arr[current++] = item;

}

// Специализированная Insert для параметра char*:

void MyArray<char*>::Insert(char* const Sitem)

{

if (current == size) return;

arr[current] = new char[strlen(item) + 1];

strcpy(arr[current++], item);

}

// Общий деструктор:

template <class T>

MyArray<T>::-MyArray () ( delete[] arr; }

// Специализированный деструктор:

MyArray<char*>::-MyArray() (


for (int i=0; i<size; i++)

delete [ ] arr[i];

delete [ ] arr;

}

А вот главная функция, тестирующая шаблон для “стандартного” типа int и для “специального” типа строк (т. е. char*):

int main(void)

{

// Создание, заполнениеи вывод MyArray<int>.

MyArray<int> *iArr;

iArr = new MyArray<int>;

int i;

for (i=0; i<DefSize; i++) iArr->Insert (i);

cout << "Integers: ";

for (i=0; KDefSize; i++)

cout << " " << iArr->Get(i);

cout<< end1<< end1;

delete iArr; // Уничтожение объекта.

// Создание, заполнение и вывод MyArray<char*>.

MyArray<char*> *sArr;

sArr = new MyArray<char*>;

for (i=0; KDefSize; i++) sArr->Insert("String!");

cout << "Strings: ";

for (i=0; KDefSize; i++)

cout << " " << sArr->Get(i) ;

cout << end1;

delete sArr; // Уничтожение объекта.

return 0;

}



Полная специализация шаблона



Можно также полностью переопределить шаблон класса для какого-то конкретного типа аргумента. Это значит, что после определения общего шаблона нужно определить специализированный шаблон класса и предусмотреть переопределения всех его элементов-функций и статических элементов данных. Ниже приводится вариант предыдущего примера, использующий такую методику:



#include <iostream.h>

#include <string.h>

const int DefSize = 4;

// Общий шаблон:

template <class T> class MyArray { protected:

int size;

int current;

T *arr;

public:

MyArray(int n = DefSize) { size = n;

current = 0;

arr = new T[size];

}

~MyArray() { delete[] arr; }

void Insert(const T &item) {

if (current == size) return;

arr[current++] = item;

}

T &Get(int idx) { return arr[idx]; } } ;

// Специализированный шаблон для char*:

class MyArray<char*> { protected:

int size;

int current; char **arr;

public:

MyArray(int n = DefSize) { size = n;

current = 0;

arr = new char*[size];

} ~MyArray() ;

void Insert(char* const &item) { if (current == size) return;



arr[current] = new char[strlen(item) + 1];

strcpy(arr[current++], item);

} char* &Get(int idx) { return arr[idx]; }

};

// Деструктор специализированного шаблона:

MyArray<char*>::~MyArray() {

for (int i=0; i<size; i++) delete [ ] arr[i] ;

delete[] arr;

}

Заметьте, что все функции- элементы общего шаблона определены теперь как встроенные, а в специализированном только деструктор определен вне тела шаблона (его нельзя объявить как встроенный, поскольку он содержит оператор цикла). В общем, полное переопределение шаблона целесообразно в том случае, когда необходима специализация большинства его элементов-функций. Главная функция ничем не отличается от функции предыдущего примера.



Функции, дружественные шаблону



В качестве “друзей” класса чаще всего объявляют различные функции-операции, в которых участвуют объекты класса. Типичным примером может служить операция передачи объекта в поток. Для шаблона класса можно определить шаблон дружественной функции (не обязательно, конечно, операции). Такой шаблон будет порождать отдельную дружественную функцию для каждого генерируемого шаблонного класса. Вот пример шаблона дружественной функции (это модификация первого примера параграфа):



#include <iostream.h>

#include <string.h>

const int DefSize = 4;

template <class T> class MyArray { protected:

int size;

int current;

T *arr;

public: MyArray(int n = DefSize) { size = n; current = 0;

arr = new T[size];

} ~MyArray();

void Insert(const T&);

T &Get(int idx) { return arr[idx]; }

friend ostream &operator“(ostream&, const MyArray<T>&);

};

// Шаблон дружественной функции-операции передачи объекта // в поток:

template <class T>

ostream &operator<<(ostream &os, const MyArray<T>&ma)

{

for (int i=0; i<ma.current; i++) os << " (" << ma.arr[i]<< "}";

return os;

}

//

// Здесь находятся общие и специализированные

// функции-элементы... //



Определенный таким образом шаблон функции-операции реализует передачу в поток всего объекта, в противоположность предыдущим примерам, где объекты шаблонных классов выводились поэлементно. Главная функция:



int main(void)

{

MyArray<int> *iArr;

iArr = new MyArray<int>;

int i;

for (i=0; KDefSize; i++) iArr->Insert (i) ;

// Вывод объекта MyArray<int>:

cout << "Integers: " << *iArr<< endl;

cout << endl;

delete iArr;

MyArray<char*> *sArr;

sArr = new MyArray<char*>;

for (i=0; i<DefSize; i++) sArr->Insert("String!");

// Вывод объекта MyArray<char*>:

cout << "Strings: "<< *sArr << endl;

delete sArr;

return 0;

}

Результат работы программы показан на рис. 10.3.



Рис. 10.3 Пример с шаблоном

дружественной

функции-операции


Содержание раздела