
pragma once Hard / Занятие 6
.docШаблоны функций и классов
Пример 3.1
Создадим функцию-шаблон, которая находит максимальное значение. Применение функции для данных различного типа продемонстрировано в функции main. Функция использует для сравнения данных операцию >.
Так как для строк операция > не определена, для них с помощью перегрузки создана специальная версия функции max. В этой версии функции используется функция strcoll, которая для строк x и y возвращает отрицательное число, если x<y, ноль, если x=y, положительное число, если x>y. При сравнении учитывается регистр и локальные настройки.
Рассматриваемую функцию-шаблон можно использовать и для объектов, если для них определена операция >. В качестве примера рассматривается класс segment (отрезок).
#include <iostream>
using namespace std;
#include <cmath>
#include <cstring>
//функция-шаблон max
template <class T> T max(T &x, T &y) {
if(x>y) return x; else return y;
}
char* max(char *x, char *y) {
if(strcoll(x,y)>0) return x; else return y;
}
//класс segment (отрезок), в котором есть перегруженная операция >
class segment {
public:
double x;
double y;
double length(){ return abs(y-x);}
segment(){x=0; y=1;}
segment(double a, double b){x=a;y=b;}
void show() {cout<<'['<<x<<';'<<y<<']';}
bool operator >(segment &Z){
return length() > Z.length();}
};
int main() {
int i=10, j=20;
cout<<"max = "<<max(i, j)<<endl;
char c1='a', c2='b';
cout<<"max = "<<max(c1,c2)<<endl;
char s1[]="ab001"; char s2[]="ab01";
cout<<"max = "<<max(s1,s2)<<endl;
//используем функцию-шаблон для объектов
segment A(-2, 9), B(25.5, 27.1), C;
A.show(); cout<<endl;
B.show(); cout<<endl;
C=max(A, B);
cout<<"max= "; C.show(); cout<<endl;
}
Пример 3.2
Создадим функцию-шаблон для сортировки массива в порядке возрастания, использующую алгоритм пузырьковой сортировки. Функцию можно использовать для сортировки объектов, если в соответствующем классе реализованы операции < и = (присваивание). В примере показано, как можно использовать эту функцию для сортировки массивов различных типов (int, double, segment). Для класса segment не потребовалось создавать перегруженную операцию присваивания, так как в нем нет динамических объектов. Побитовое копирование, которое при присваивании выполняется по умолчанию, в данном случае работает корректно.
#include <iostream>
using namespace std;
#include <cmath>
//функция-шаблон sort
template <class T> void sort(T *x, int n) {
int i,j; T r;
for (i=0;i<n-1;i++)
for (j=0;j<n-i-1;j++)
if(x[j]>x[j+1]){r=x[j]; x[j]=x[j+1]; x[j+1]=r;}
}
//класс segment (отрезок), в котором есть перегруженная операция >
class segment {
public:
double x;
double y;
double length(){ return abs(y-x);}
segment(){x=0; y=1;}
segment(double a, double b){x=a;y=b;}
void show() {cout<<'['<<x<<';'<<y<<']';}
bool operator >(segment &Z){
return length() > Z.length();}
};
int main() {
int i;
int P[4]={3, 2, 7, -1};
for (i=0; i<4; i++) {cout<<P[i]<<" ";} cout<<endl;
sort(P,4);
for (i=0; i<4; i++) {cout<<P[i]<<" ";} cout<<endl;
double Q[5]={-1.3, 8.2, 0.7, -1, 2.7};
for (i=0; i<5; i++) {cout<<Q[i]<<" ";} cout<<endl;
sort(Q,5);
for (i=0; i<5; i++) {cout<<Q[i]<<" ";} cout<<endl;
segment V[3];
V[0].x=0; V[1].x=-1.5; V[2].x=1.8;
V[0].y=3; V[1].y=5.2; V[2].y=4.3;
for (i=0; i<3; i++) {V[i].show(); cout<<" ";} cout<<endl;
sort(V,3);
for (i=0; i<3; i++) {V[i].show(); cout<<" ";} cout<<endl;
}
Пример 3.3
Создадим шаблонный класс stack, который позволит использовать стеки для хранения объектов различных типов. В функции main создаются 3 стека для хранения целых чисел, символов и указателей на объекты segment.
При объявлении шаблонного метода вне класса используется следующий синтаксис:
template <class Tип1 [,…, class типN]>
ТипРезультата ИмяКласса <Tип1 [,…, типN]>::
ИмяМетода(ПараметрыМетода)
В данном случае Tип1,…, типN – формальные параметры-типы. Для создания объектов с помощью шаблонного класса используется конструкция
ИмяКласса <Tип1 [,…, типN]> ИмяПеременной [(параметры_конструктора)];
При создании объекта внутри угловых скобок указываются реальные типы данных.
#include <iostream>
using namespace std;
template <class T> class stack {
struct Elem{
T d;
Elem *next;
};
Elem *top; // указатель на вершину стека
public:
stack () {top=NULL;}
stack (T x) {top=NULL; put(x);}
~stack ();
void put (T x);
T get();
};
class segment {
public:
double x;
double y;
double length(){ return abs(y-x);}
segment(){x=0; y=1;}
segment(double a, double b){x=a;y=b;}
void show() {cout<<'['<<x<<';'<<y<<']';}
bool operator >(segment &Z){
return length() > Z.length();}
};
template <class T> stack <T>::~stack ()
{
if (top!=NULL) {
Elem *p = top;
while (top){
p = top->next;
delete top;
top=p;
}
}
}
template <class T> void stack <T>::put (T x)
{
Elem *p = new Elem;
p->d = x; p->next = top;
top = p;
}
template <class T> T stack <T>::get()
{
if (top==NULL)
{
cout << " stack is empty";
return 0;
}
else
{
Elem *p = top;
top = top->next;
T d = p->d;
delete p;
return d;
}
}
int main()
{
stack <int> P;
for (int i=1;i<10;i++) P.put(i);
cout<<"P: ";
for (int i=1;i<10;i++) cout<<P.get()<<' ';
cout<<endl;
stack <char> Q;
for (char c='a';c<='z';c++) Q.put(c);
cout<<"Q: ";
while(char c=Q.get()) cout<<c<<' ';
cout<<endl;
segment A(-2, 9), B(25.5, 27.1), C(0.5,7.2);
stack <segment *> R;
R.put(&A); R.put(&B); R.put(&C);
cout<<"R: ";
while(segment *s=R.get()){s->show();cout<<' ';}
cout<<endl;
}
Задания:
Создайте функцию шаблон, удаляющую из массива повторяющиеся элементы. Оставшиеся элементы сдвигаются в начало массива с сохранением исходного порядка. Образовавшиеся после сдвига неиспользуемые элементы в конце массива обнуляются.