Код программ привожу не полностью! Тренировок в виде решения предыдущих ЛР было множество, к тому же у каждого свои функции и решения. Поднимайте коды ЛР6 и класса Матрица и вперед!.
Данную ЛР можно делать двумя способами.
Создать простой шаблон функции.
Создать шаблон класса.
Сначала рассмотрим первый вариант на примере следующей задачи: Посчитать количество пар равных чисел, находящихся на одинаковых местах. У нас есть 2 одномерных массива, сравниваем их поэлементно и выдаем ответ.
template <typename T> int compare1(T* v1, T* v2, int n) { int k = 0; for (int i = 0; i < n; i++) if (v1[i] == v2[i]) k++; return k; }
|
Шаблон функции. На вход подаются два вектора одного типа и их размер. На выходе имеем количество, поэтому тут переменная k целого типа. Если бы считали сумму или произведение, то переменная была бы того же типа, что и входной массив. |
//главная int main(void) {
setlocale(LC_ALL, "Russian"); int i, j, n, k; cout << "Введите размер массива "; do { cin >> n; } while (n < 2);
|
|
int* v1 = new int[n]; cout << "Первый массив: " << endl; for (i = 0; i < n; i++) cin >> v1[i]; cout << "Второй массив" << endl; int* v2 = new int[n]; for (i = 0; i < n; i++) cin >> v2[i]; |
Отрабатываем сначала на целочисленном типе. Далее заменяем выделенный тип на double, убеждаемся, что шаблон функции работает корректно. |
k = compare1(v1, v2, n); if (k == 0) cout << "Повторов на одинаковых местах нет"; else cout << k << " одинаковых чисел на соответствующих местах" << endl;
|
Вызываем функцию, проверяем, что все работает корректно.. |
delete[] v1; delete[] v2;
system("pause"); return 0; } |
|
После того, как отработаете на стандартных типах, подставляем complex вместо double и смотрим, какие перегрузки операторов потребуются в классе complex. В моем случае нужны перегрузка сравнения на равенство и оператора потокового ввода. |
|
class complex { double re, im; public:
void set_c(double Re = 0, double Im = 0) { re = Re; im = Im; } double get_c_re() { return re; } double get_c_im() { return im; }
bool operator== (complex b) { return (re == b.re && im == b.im); }
friend istream& operator>>(istream& in, complex& c); };
istream& operator>>(istream& in, complex& c) { // return (in >> c.re >> c.im); //1. вариант. Без лишних подсказок
//2 вариант (подробнее) cout << "real = "; in >> c.re; cout << "image = "; in >> c.im; return (in); }
|
! Рекомендуется сделать в своих работах не только минимум нужных перегрузок операторов, но и другие, например, для вывода информации о комплексном числе. |
Теперь рассмотрим более сложный пример – шаблон класса. Для решения моей задачи потребуется класс vect. Я уже приводила пример кода в пояснениях к ЛР 6.
class vect { complex* base; int size; public: vect(int n = 1) { size = n; base = new complex[size]; }
~vect() { delete[] base; } void fill_vect(); void print(); void print_table();
int get_size() { return size; } int& set_size() { return size; }
complex get_elem(int i) { return base[i]; } complex& set_elem(int i) {return base[i]; } complex& elem(int i) { return base[i]; }
int compare(vect& v2);
friend ostream& operator<<(ostream& out, const vect& v);
}; |
Метод print() можно заменить на перегрузку оператора вывода (дружественная функция внизу класса).
При создании шаблона класса надо обратить внимание не только на поля, но и на методы класса. Например, в конструкторе, где выделяется память, требуется тоже установить тип шаблона.
Обязательно надо обратить внимание на дружественные функции, там тоже указывается тип. |
Пример шаблона класса vect. Новое выделено голубым.
template <class F> class vect { F* base; int size; public: vect(int n = 1) { size = n; base = new F[size]; } ~vect() { delete[] base; } void fill_vect(); int get_size() { return size; } int& set_size() { return size; } F get_elem(int i) { return base[i]; } F& set_elem(int i) { return base[i]; } F& elem(int i) { return base[i]; }
int compare(vect<F>& v2);
friend ostream& operator<< <F>(ostream& out, const vect<F>& v); };
|
Изменяются только тип значений массива, поэтому везде, где идет обращение к массиву, прописываем тип шаблона (какой буквой укажете – не сильно имеет значение. Главное, чтобы имя удовлетворяло допустимым именам в С++. |
template <class T> ostream& operator<< (ostream& out, const vect<T>& v) { for (int i = 0; i < v.size; i++) out << v.base[i] << " "; return out; }
|
Обратите внимание, что в шаблоне этой перегрузки уже не везде ставится тип в угловых скобочках. |
template <class T> void vect<T>::fill_vect() { for (int i = 0; i < size; i++) cin >> base[i]; }
template <class T> int vect<T>::compare(vect<T>& v2) { int k = 0; for (int i = 0; i < size; i++) if (base[i] == v2.base[i]) k++; return k; }
|
|
int main(void) { setlocale(LC_ALL, "Russian"); int i, j, n, k; cout << "Введите размер массива "; do { cin >> n; } while (n < 2);
vect<complex> mas(n); cout << "Первый вектор" << endl; mas.fill_vect();
|
В главной функции получим следующий код. Здесь в угловых скобочках надо указать тип, с которым будет работать шаблон класса. |
vect<complex> newmas(n); cout << "Второй вектор" << endl; for (i = 0; i < n; i++) cin >> newmas.set_elem(i);
|
Второй вектор заполнила непосредственно из main, чтобы убедиться в работоспособности методов. |
cout << endl << "Наши вектора" << endl; cout << mas << endl; cout << newmas << endl; |
После перегрузки оператора вывода для класса Вектор, наши массивы можно выводить коротко и просто |
k = mas.compare(newmas); if (k == 0) cout << "Повторов на одинаковых местах нет"; else cout << "Одинаковых чисел на соответствующих местах " << k << endl;
system("pause"); return 0; }
|
Как и прежде, в k заносим результат работы метода сравнения, далее выводим нужную информацию на экран. |
Рекомендуемая литература:
Шаблоны функций https://foxford.ru/wiki/informatika/shablony-funktsiy-v-s (отдельно видео на Ютубе https://youtu.be/HTBkRGXTNoo )
Шаблоны классов https://foxford.ru/wiki/informatika/shablony-klassov-v-s (отдельно видео https://youtu.be/yPGD6zlxmJU )
Соответствующие темы в ранее упомянутых книгах. Например, в пособии Русоновой с. 97 и с. 166.