Пример 6.4. Сглаживание заданной вещественной матрицы, работа с файлами




Операция сглаживания матрицы дает новую матрицу того же размера, каждый элемент которой получается как среднее арифметическое имею­щихся соседей соответствующего элемента исходной матрицы.

Построить резуль­тат сглаживания заданной вещественной матрицы размером 10 на 10. В сглаженной матрице найти сумму модулей элементов, расположенных выше глав­ной диагонали. Ввод и вовод данных в программе осуществить с помощью файла. UML-диаграмма этого алгоритма приведена на рисунке 6.4.

Рисунок 6.4 - UML-диаграмма деятельности для примера 6.4

Листинг 6.5

 

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <tchar.h>

#include <fstream>

#include <iomanip>

using namespace std;

 

int main()

{

const int nrow=10;

const int ncol=10;

 

ifstream fin("input.txt",ios::in);

if (!fin)

{

cout<<"Can't find input.txt"<<endl;

return 1;

}

ofstream fout("output.txt");

if (!fout)

{

cout<<"Write falure: check permission"<<endl;

return 1;

}

int k,l,k1,l1,counter,i,j;

double sum,sumdiag=0;

//заполнение массива из файла

double a[nrow][ncol];

 

cout << "Чтение данных из файла..." << endl;

for(i=0;i<nrow;i++)

for(j=0;j<ncol;j++) fin>>a[i][j];

double m[nrow][ncol];

 

cout<<"Обработка данных..."<<endl;

//процедура сортировки

counter=0;sum=0;l=0;l1=0;

for(i=0;i<nrow;i++)

for(j=0;j<ncol;j++)

{

k=i-1;

k1=i+1;

if (k<0) k++;

if (k1>ncol-1) k1--;

if ((j<=ncol-1)&&(j>=ncol-i)) sumdiag = sumdiag + a[i][j];

for(k;k<=k1;k++)

{

l=j-1;

l1=j+1;

if (l<0) l++;

if (l1>ncol-1) l1--;

for(l;l<=l1;l++)

if ((k==i)&&(l==j)) continue;

else

{

sum=sum+a[k][l];

counter++;

}

}

m[i][j]=(float) sum/counter;

sum=0;

counter=0;

}

 

//запись отсортированного массива в файл

Cout << "Запись результатов обработки в файл..." << endl;

for(i=0;i<nrow;i++)

{

for(j=0;j<ncol;j++)

fout<<setw(5)<<left<<setprecision(3)

<<m[i][j]<<" ";

fout<<endl;

}

Fout << endl;

Fout << "Сумма всех эл-ов ниже глав. диагонали:" << setw(5) << setprecision(9) << sumdiag << endl;

cout << "Обработка закончена!" << endl;

return 0;

}

Рисунок 6.5 – Файл для входных данных

Рисунок 6.6 – Файл для выходных данных

Рисунок 6.7 – Вывод программы на экран

 

Пример 6.5. Определение количества отрицательных элементов в тех строках данной целочисленной прямоугольной матрицы, которые содержат хотя бы один нулевой элемент

Дана целочисленная прямоугольная матрица. Определить количество отрицательных элементов в тех строках, которые содержат хотя бы один нулевой элемент. UML-диаграмма этого алгоритма приведена на рисунке 6.8.

Рисунок 6.8 - UML-диаграмма деятельности для примера 6.5

Листинг 6.6

 

#include "stdafx.h"

#include <conio.h>

#include <windows.h>

#include <math.h>

#include <iostream>

#include <time.h>

using namespace std;

 

int _tmain(int argc, _TCHAR* argv[])

{

setlocale(LC_ALL, "Russian");

srand((unsigned)time(NULL));

int m,n,h,c,i,j,ch;

 

cout << "Лабораторная работа № 6\n";

cout << "\nЗадание\nДана целочисленная прямоугольная матрица. Определить:\ количество отрицательных элементов в тех строках,\nкоторые содержат хотя бы один нулевой элемент.";

cout << "\n Введите размерность массива\n";

cin >> n;

cin >> m;

 

int **a = new int *[n];

for(i = 0; i < n; i++) a[i] = new int [m];

cout << "\nВыберите способ ввода массива";

cout << "\n1. Ввести массив с клавиатуры.\n2. Заполнить массив случайным образом.\n";

cin>>ch;

if (ch==1)

{

cout << "\n Введите элементы массива\n"<<endl;

for(i = 0; i < n; i++)

for(j = 0; j < m; j++) cin >> a[i][j];

for(i = 0; i < n; i++)

{

for(j = 0; j < m; j++)

cout << a[i][j] << ' ';

cout << endl;

}

}

if (ch == 2)

{

for(i = 0; i < n; i++)

for(j = 0; j < m; j++) a[i][j]=rand()%20;

for(i = 0; i < n; i++)

{

for(j = 0; j < m; j++)

cout << a[i][j] << ' ';

cout << endl;

}

}

h = 0;

for(i = 0; i < n; i++)

{

for (j = 0; j < m; j++)

if (a[i][j] < 0)

h++;

for (j = 0; j < m; j++)

if (a[i][j] == 0)

{

cout << "\nНомер строки\n" << i;

cout << "\nЧисло отрицательных элементов\n" << h;

h = 0;

}

else

cout << "\nНет нулевых элементов\n";

}

getch();

return 0;

}

Аппаратура и материалы. Для выполнения лабораторной работы необходим персональный компьютер со следующими характеристиками: процессор Intel Pentium-совместимый с тактовой частотой 800 МГц и выше, оперативная память - не менее 64 Мбайт, свободное дисковое пространство - не менее 500 Мбайт, устройство для чтения компакт-дисков, монитор типа Super VGA (число цветов от 256) с диагональю не менее 15². Программное обеспечение - операционная система Windows2000/XP и выше, среда разработки приложений Microsoft Visual Studio.

Указания по технике безопасности. Техника безопасности при выполнении лабораторной работы совпадает с общепринятой для пользователей персональных компьютеров, самостоятельно не производить ремонт персонального компьютера, установку и удаление программного обеспечения; в случае неисправности персонального компьютера сообщить об этом обслуживающему персоналу лаборатории (оператору, администратору); соблюдать правила техники безопасности при работе с электрооборудованием; не касаться электрических розеток металлическими предметами; рабочее место пользователя персонального компьютера должно содержаться в чистоте; не разрешается возле персонального компьютера принимать пищу, напитки.

Методика и порядок выполнения работы. Перед выполнением лабораторной работы каждый студент получает индивидуальное задание. Защита лабораторной работы происходит только после его выполнения (индивидуального задания). При защите лабораторной работы студент отвечает на контрольные вопросы, приведенные в конце, и поясняет выполненное индивидуальное задание. Ход защиты лабораторной работы контролируется преподавателем.Порядок выполнения работы:

1.Проработать примеры, приведенные в лабораторной работе.

2. Составить программу с использованием двумерных локальных массивов для решения задачи. Размерности локальных массивов задавать именованны­ми константами, значения элементов массива - в списке инициализации. Номер варианта определяется по формуле , где - номер студента по списку преподавателя.

Индивидуальное задание №1. Вариант:

1. Дана целочисленная прямоугольная матрица. Определить:

1) количество строк, не содержащих ни одного нулевого элемента;

2) максимальное из чисел, встречающихся в заданной матрице более одного раза.

 

2. Дана целочисленная прямоугольная матрица. Определить количество столбцов, не содержащих ни одного нулевого элемента.

Характеристикой строки целочисленной матрицы назовем сумму ее положитель­ных четных элементов. Переставляя строки заданной матрицы, расположить их в соответствии с ростом характеристик.

 

3. Дана целочисленная прямоугольная матрица. Определить:

1) количество столбцов, содержащих хотя бы один нулевой элемент;

2) номер строки, в которой находится самая длинная серия одинаковых элементов.

 

4. Дана целочисленная квадратная матрица. Определить:

1) произведение элементов в тех строках, которые не содержат отрицательных элементов;

2) максимум среди сумм элементов диагоналей, параллельных главной диагонали матрицы.

 

5. Дана целочисленная квадратная матрица. Определить:

1) сумму элементов в тех столбцах, которые не содержат отрицательных эле­ментов;

2) минимум среди сумм модулей элементов диагоналей, параллельных побочной диагонали матрицы.

 

6. Для заданной матрицы размером 8 на 8 найти такие k, что k -я строка матрицы совпадает с k-м столбцом.

Найти сумму элементов в тех строках, которые содержат хотя бы один отрица­тельный элемент.

 

7. Характеристикой столбца целочисленной матрицы назовем сумму модулей его отрицательных нечетных элементов. Переставляя столбцы заданной матрицы, рас­положить их в соответствий с ростом характеристик.

Найти сумму элементов в тех столбцах, которые содержат хотя бы один отрица­тельный элемент.

 

8. Соседями элемента Aj в матрице назовем элементы Аk с i - 1 < k < i+1, j-1 < 1 < j + 1, (k, 1) / (i, j). Операция сглаживания матрицы дает новую матрицу того же размера, каждый элемент которой получается как среднее арифметическое имею­щихся соседей соответствующего элемента исходной матрицы. Построить резуль­тат сглаживания заданной вещественной матрицы размером 7 на 7. В сглаженной матрице найти сумму модулей элементов, расположенных ниже глав­ной диагонали.

 

9. Элемент матрицы называется локальным минимумом, если он строго меньше всех имеющихся у него соседей. Подсчитать количество локальных минимумов задан­ной матрицы размером 10 на 10.
Найти сумму модулей элементов, расположенных выше главной диагонали.

 

10. Коэффициенты системы линейных уравнений заданы в виде прямоугольной матри­цы. С помощью допустимых преобразований привести систему к треугольному виду. Найти количество строк, среднее арифметическое элементов которых меньше за­данной величины.

 

11. Уплотнить заданную матрицу, удаляя из нее строки и столбцы, заполненные нулями. Найти номер первой из строк, содержащих хотя бы один положительный элемент.

 

12. Осуществить циклический сдвиг элементов прямоугольной матрицы на п элемен­тов вправо или вниз (в зависимости от введенного режима), п может быть больше количества элементов в строке или столбце.

 

13. Осуществить циклический сдвиг элементов квадратной матрицы размерности М х N вправо на к элементов таким образом: элементы 1-й строки сдвигаются в последний столбец сверху вниз, из него - в последнюю строку справа налево, из нее - в первый столбец снизу вверх, из него - в первую строку; для остальных элементов - аналогично.

 

14. Дана целочисленная прямоугольная матрица. Определить номер первого из столб­цов, содержащих хотя бы один нулевой элемент.

Характеристикой строки целочисленной матрицы назовем сумму ее отрицатель­ных четных элементов. Переставляя строки заданной матрицы, расположить их в соответствии с убыванием характеристик.

 

15. Упорядочить строки целочисленной прямоугольной матрицы по возрастанию ко­личества одинаковых элементов в каждой строке.

Найти номер первого из столбцов, не содержащих ни одного отрицательного эле­мента.

 

16. Путем перестановки элементов квадратной вещественной матрицы добиться того, чтобы ее максимальный элемент находился в левом верхнем углу, следующий по величине - в позиции (2,2), следующий по величине - в позиции (3,3) и т. д., за­полнив таким образом всю главную диагональ. Найти номер первой из строк, не содержащих ни одного положительного эле­мента.

 

17. Дана целочисленная прямоугольная матрица. Определить:

1) количество строк, содержащих хотя бы один нулевой элемент;

2) номер столбца, в котором находится самая длинная серия одинаковых элементов.

 

18. Дана целочисленная квадратная матрица. Определить:

1) сумму элементов в тех строках, которые не содержат отрицательных элементов;

2) минимум среди сумм элементов диагоналей, параллельных главной диагонали матрицы.

 

19. Дана целочисленная прямоугольная матрица. Определить:

1) количество положительных элементов в тех строках, которые не содержат нулевых элементов;

2) номера строк и столбцов всех седловых точек матрицы.

Примечание. Матрица А имеет седловую точку АР если АР является минималь­ным элементом в i-й строке и максимальным в j-м столбце.

 

3. Составить программу с использованием двумерных динамических массивов для решения задачи согласно варианту индивидуального задания №1.

Содержание отчета и его форма. Отчет по лабораторной работе должен состоять из:

1. Названия лабораторной работы.

2. Цели и содержания лабораторной работы.

3. Ответов на контрольные вопросы лабораторной работы.

4. Формулировки индивидуальных заданий и порядка их выполнения.

Отчет о выполнении лабораторной работы в письменном виде сдается преподавателю.

Вопросы для защиты работы

1. Как представляется в C++ двумерный массив?

2. Где и каким образом хранится двумерный массив?

3. В каких пределах изменяются индексы двумерного массива?

4. Какими способами можно описать двумерный массив?

5. Какие действия вы­полняются для каждой строки при вычислении количества положительных элементов?

6. В каком месте программы следует записывать операторы инициализации накапливаемых в цикле величин?

7. Каким образом в динамической области памяти можно создавать двумерные массивы?

8. Способы создания динамического массива.

9. Каким образом производится обращение к элементам динамических массивов?

 

Пример выполнения лабораторной работы №6:

1. Индивидуальное задание №1:

1.1. Постановка задачи:

Составить программу с использованием двумерных локальных массивов для решения задачи. Размерности локальных массивов задавать именованны­ми константами, значения элементов массива - в списке инициализации.

Задача: дана целочисленная прямоугольная матрица. Определить:

1) сумму элементов в тех строках, которые содержат хотя бы один отрицательный элемент;

2) номера строк и столбцов всех седловых точек матрицы.

Примечание. Матрица А имеет седловую точку As, если As является минималь­ным элементом в i-й строке и максимальным в j-м столбце.

1.2. UML-диаграмма:

1.3. Листинг программы:

// Лабораторная работа №6

// Индивидуальное задание №1

 

#include "stdafx.h"

#include <iostream>

#include "conio.h"

#include "math.h"

#include "windows.h"

 

using namespace std;

 

int _tmain(int argc, _TCHAR* argv[])

{

setlocale(LC_ALL, "Russian");

const int nrow = 3, ncol = 5;

int A[nrow][ncol];

int i, j, summ;

 

cout<<"Лабораторная работа № 6\n"

 

<<"\n\nИндивидуальное задание № 1:\n"

<<"\nСоставить программу с использованием двумерных локальных массивов для\n"

<<"\nрешения задачи. Размерности локальных массивов задавать именованными\n"

<<"\nконстантами, значения элементов массива - в списке инициализации.\n"

<<"\n\nЗадача: дана целочисленная прямоугольная матрица. Определить:\n"

<<"сумму элементов в тех строках, которые содержат хотя бы один\n"

<<"\nотрицательный элемент;\n"

<<"\n2) номера строк и столбцов всех седловых точек матрицы.\n"

<<"\n\nПримечание: матрица А имеет седловую точку As, если Аs является\n"

<<"\nминимальным элементом в i-й строке и максимальным в j-м столбце.\n"

<<"\n\nРабота программы:\n"

 

<<"\nВведите элементы массива: \n\n";

 

for (i = 0; i < nrow; i++)

{

for (j = 0; j < ncol; j++)

{

cout << "A[" << i << "][" << j << "] = ";

cin >> A[i][j];

}

}

 

cout << "\n1) ";

for (i = 0; i < nrow; i++)

{

bool flag = false;

summ = 0;

for (j = 0; j < ncol; j++)

{

summ += A[i][j];

if(A[i][j] < 0)

flag = true;

}

if(flag == true)

{

cout<<"Сумма элементов строки "<< i;

cout<<" с отрицательным элементом"<< " = " << summ << "\n\n";

}

}

cout<<"\n2) ";

for (i = 0; i < nrow; i++)

{

int min, max;

int tempValue; // временная переменная

min = 0;

tempValue = A[i][0];

// поиск минимального в строке элемента

for (j = 0; j < ncol; j++)

{

if(A[i][j] < tempValue)

{

min = j;

tempValue = A[i][j];

}

}

// поиск максимального в столбце элемента

max = 0;

tempValue = A[0][min];

for(j = 0; j < nrow; j++)

{

if(A[j][min] > tempValue)

{

max = j;

tempValue = A[j][min];

}

}

if(i == max)

{

cout<<"Седловая точка: "<< "As[" << max << "][" << min << "]";

}

}

 

getch();

return 0;

}

1.4. Результаты работы программы:

2. Индивидуальное задание №2:

2.1. Постановка задачи:

Составить программу с использованием двумерных динамических массивов для решения задачи индивидуального задания №1.

2.2. UML-диаграмма:

2.3. Листинг программы:

// Лабораторная работа №6

// Индивидуальное задание №2

 

#include "stdafx.h"

#include <iostream>

#include "conio.h"

#include "math.h"

#include "windows.h"

 

using namespace std;

 

int _tmain(int argc, _TCHAR* argv[])

{

setlocale(LC_ALL, "Russian");

int nrow, ncol, i, j, summ;

 

cout<<"Лабораторная работа № 6\n";

 

cout<<"\n\nИндивидуальное задание № 2:\n";

cout<<"\nСоставить программу с использованием двумерных динамических\n";

cout<<"\nмассивов для решения задачи индивидуального задания №1.\n";

cout<<"\n\nРабота программы:\n";

 

cout<<"\nВведите количество строк и столбцов:\n\n"<< "i = ";

cin >> nrow;

cout<< "j = ";

cin >> ncol;

 

int **A = new int *[nrow];

cout<<"\nВведите элементы массива: \n\n";

for (i = 0; i < nrow; i++)

{

A[i] = new int[ncol];

for (j = 0; j < ncol; j++)

{

cout << "A[" << i << "][" << j << "] = ";

cin >> A[i][j];

}

}

cout<<"\n1) ";

for (i = 0; i < nrow; i++)

{

bool flag = false;

summ = 0;

for (j = 0; j < ncol; j++)

{

summ += A[i][j];

if(A[i][j] < 0)

flag = true;

}

if(flag == true)

{

cout<<"Сумма элементов строки "<< i;

cout<<" с отрицательным элементом"<< " = " << summ << "\n\n";

}

}

 

cout<<"\n2) ";

for (i = 0; i < nrow; i++)

{

int min, max;

int tempValue; // временная переменная

min = 0;

tempValue = A[i][0];

// поиск минимального в строке элемента

for (j = 0; j < ncol; j++)

{

if(A[i][j] < tempValue)

{

min = j;

tempValue = A[i][j];

}

}

// поиск максимального в столбце элемента

max = 0;

tempValue = A[0][min];

for(j = 0; j < nrow; j++)

{

if(A[j][min] > tempValue)

{

max = j;

tempValue = A[j][min];

}

}

if(i == max)

{

cout<<"Седловая точка: "<< "As[" << max << "][" << min << "]";

}

}

 

getch();

return 0;

}

2.4. Результаты работы программы:

 

 

 

 

Лабораторная работа № 7

Функции и перегрузка в языке С++

Ход работы:

 

Получить и изучить навыки создания функций в языке программирования С++, изучить перегрузки функций.

Под перегрузкой функции понимается, определение нескольких функций (две или больше) с одинаковым именем, но различными параметрами. Наборы параметров перегруженных функций могут отличаться порядком следования, количеством, типом. Таким образом перегрузка функций нужна для того, чтобы избежать дублирования имён функций, выполняющих сходные действия, но с различной программной логикой. Например, рассмотрим функцию areaRectangle(), которая вычисляет площадь прямоугольника.

Это функция с двумя параметрами типа float, причём аргументы передаваемые в функцию должны быть в сантиметрах, возвращаемое значение типа float — тоже в сантиметрах.

Предположим, что ваши исходные данные (стороны прямоугольника) заданы в метрах и сантиметрах, например такие: a = 2м 35 см; b = 1м 86 см. В таком случае, удобно было бы использовать функцию с четырьмя параметрами. То есть, каждая длинна сторон прямоугольника передаётся в функцию по двум параметрам: метры и сантиметры.

int main()

{

areaRectangle(float, float) //функция, вычисляющая площадь прямоугольника с двумя параметрами a(см) и b(см)

{

return a * b; // умножаем длинны сторон прямоугольника и возвращаем полученное произведение

}

 

 

В теле функции значения, которые передавались в метрах (a_m и b_m) переводятся в сантиметры и суммируются с значениями a_sm b_sm, после чего перемножаем суммы и получаем площадь прямоугольника в см. Конечно же можно было перевести исходные данные в сантиметры и пользоваться первой функцией.

Есть две функции, с разной сигнатурой, но одинаковыми именами (перегруженные функции). Сигнатура – это комбинация имени функции с её параметрами. Данные функции носят название перегруженные. А вызов перегруженных функций ничем не отличается от вызова обычных функций, например:

areaRectangle(32, 43); // будет вызвана функция, вычисляющая площадь прямоугольника с двумя параметрами a(см) и b(см)

areaRectangle(4, 43, 2, 12); // будет вызвана функция, вычисляющая площадь прямоугольника с 4-мя параметрами a(м) a(см); b(м) b(cм)

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

#include "stdafx.h"

#include <iostream>

#include "fstream"

#include <string>

#include <cstring>

#include "clocale"

#include "ctime"

#include "conio.h"

#include "stdio.h"

#include "windows.h"

#include "stdlib.h"

#include <iostream>

#include <math.h> // Перегрузка операторов.cpp: определяет точку входа для консольного приложения.

class funczii;

using namespace std;

 

 

int main()

 

{

setlocale(LC_ALL, "rus");

float S1;

float S2;

float a;

float b;

void areaRectangle(float a, float b);

void areaRectangle(float a_m, float a_sm, float b_m, float b_sm);

{

cout << "S1 = " << areaRectangle(32, 43) << endl; // вызов перегруженной функции 1

cout << "S2 = " << areaRectangle(4, 43, 2, 12) << endl; // вызов перегруженной функции 2

cin >> a;

cin >> b;

return 0;

}

// перегруженная функция 1

void areaRectangle(float a, float b); //функция, вычисляющая площадь прямоугольника с двумя параметрами a(см) и b(см)

{

float a;

float b;

return a * b; // умножаем длинны сторон прямоугольника и возвращаем полученное произведение

}

float a_m;

float a_sm;

float b_m;

float b_sm;

// перегруженная функция 2

void areaRectangle(float a_m, float a_sm, float b_m, float b_sm); // функция, вычисляющая площадь прямоугольника с 4-мя параметрами a(м) a(см); b(м) b(cм)

{

return (a_m * 100 + a_sm) * (b_m * 100 + b_sm);

}

 

system ("pause");

int getch();

return 0;

}

 

Результат работы программы:

2.5. Результаты работы программы:

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

Затем, научившись объявлять, определять и использовать функции в программах, познакомимся с перегрузкой – еще одним аспектом в C++. Перегрузка позволяет иметь несколько одноименных функций, выполняющих схожие операции над аргументами разных типов.
Ознакомившись, уже воспользовались предопределенной перегруженной функцией. Например, для вычисления выражения:

1 + 3

вызывается операция целочисленного сложения, тогда как вычисление выражения

1.0 + 3.0

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

Как и в случае со встроенной операцией сложения, нам может понадобиться набор функций, выполняющих одно и то же действие, но над параметрами различных типов. Предположим, что мы хотим определить функции, возвращающие наибольшее из переданных значений параметров. Если бы не было перегрузки, пришлось бы каждой такой функции присвоить уникальное имя. Например, семейство функций max() могло бы выглядеть следующим образом:

int i_max(int, int);

int vi_max(const vector<int> &);

int matrix_max(const matrix &);

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

int ix = max(j, k);

vector<int> vec;

//...

int iy = max(vec);

Этот подход оказывается чрезвычайно полезным во многих ситуациях.

В C++ двум или более функциям может быть дано одно и то же имя при условии, что их списки параметров различаются либо числом параметров, либо их типами. В данном примере мы объявляем перегруженную функцию max():

int max (int, int);int max(const vector<int> &);int max(const matrix &);

Для каждого перегруженного объявления требуется отдельное определение функции max() с соответствующим списком параметров.
Если в некоторой области видимости имя функции объявлено более одного раза, то второе (и последующие) объявление интерпретируется компилятором так:

  • если списки параметров двух функций отличаются числом или типами параметров, то функции считаются перегруженными:
· // перегруженные функции· void print(const string &);void print(vector<int> &);
  • если тип возвращаемого значения и списки параметров в объявлениях двух функций одинаковы, то второе объявление считается повторным:
· // объявления одной и той же функции· void print(const string &str);void print(const string &);

Имена параметров при сравнении объявлений во внимание не принимаются;
если списки параметров двух функций одинаковы, но типы возвращаемых значений различны, то второе объявление считается неправильным (несогласованным с первым) и помечается компилятором как ошибка:

unsigned int max(int i1, int i2); int max(int i1, int i2);
// ошибка: отличаются только типы
// возвращаемых значений

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

// объявления одной и той же функцииint max (int *ia, int sz);int max (int *ia, int = 10);

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

// typedef не вводит нового типаtypedef double DOLLAR;// ошибка: одинаковые списки параметров, но разные типы// возвращаемых значенийextern DOLLAR calc(DOLLAR);extern int calc(double);

Спецификаторы const или volatile при подобном сравнении не принимаются во внимание. Так, следующие два объявления считаются одинаковыми:

// объявляют одну и ту же функциюvoid f(int);void f(const int);

Спецификатор const важен только внутри определения функции: он показывает, что в теле функции запрещено изменять значение параметра. Однако аргумент, передаваемый по значению, можно использовать в теле функции как обычную инициированную переменную: вне функции изменения не видны. (Способы передачи аргументов, в частности передача по значению, обсуждаются в разделе.) Добавление спецификатора const к параметру, передаваемому по значению, не влияет на его интерпретацию. Функции, объявленной как f(int), может быть передано любое значение типа int, равно как и функции f(const int). Поскольку они обе принимают одно и то же множество значений аргумента, то приведенные объявления не считаются перегруженными. f() можно определить как

void f(int i) { }

или как

void f(const int i) { }

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

// объявляются разные функцииvoid f(int*);void f(const int*); // и здесь объявляются разные функции
void f(int&);
void f(const int&);

В C++ двум или более функциям может быть дано одно и то же имя при условии, что их списки параметров различаются либо числом параметров, либо их типами. В данном примере мы объявляем перегруженную функцию max():

int max (int, int);int max(const vector<int> &);int max(const matrix &);

Для каждого перегруженного объявления требуется отдельное определение функции max() с соответствующим списком параметров.
Если в некоторой области видимости имя функции объявлено более одного раза, то второе (и последующие) объявление интерпретируется компилятором так:

  • если списки параметров двух функций отличаются числом или типами параметров, то функции считаются перегруженными:
· // перегруженные функции· void print(const string &);void print(vector<int> &);
  • если тип возвращаемого значения и списки параметров в объявлениях двух функций одинаковы, то второе объявление считается повторным:
· // объявления одной и той же функции· void print(const string &str);void print(const string &);

Имена параметров при сравнении объявлений во внимание не принимаются;
если списки параметров двух функций одинаковы, но типы возвращаемых значений различны, то второе объявление считается неправильным (несогласованным с первым) и помечается компилятором как ошибка:

unsigned int max(int i1, int i2); int max(int i1, int i2);
// ошибка: отличаются только типы
// возвращаемых значений

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

// объявления одной и той же функцииint max (int *ia, int sz);int max (int *ia, int = 10);

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

// typedef не вводит нового типаtypedef double DOLLAR;// ошибка: одинаковые списки параметров, но разные типы// возвращаемых значенийextern DOLLAR calc(DOLLAR);extern int calc(double);

Спецификаторы const или volatile при подобном сравнении не принимаются во внимание. Так, следующие два объявления считаются одинаковыми:

// объявляют одну и ту же функциюvoid f(int);void f(const int);

Спецификатор const важен только внутри определения функции: он показывает, что в теле функции запрещено изменять значение параметра. Однако аргумент, передаваемый по значению, можно использовать в теле функции как обычную инициированную переменную: вне функции изменения не видны. (Способы передачи аргументов, в частности передача по значению, обсуждаются в разделе 7.3.) Добавление спецификатора const к параметру, передаваемому по значению, не влияет на его интерпретацию. Функции, объявленной как f(int), может быть передано любое значение типа int, равно как и функции f(const int). Поскольку они обе принимают одно и то же множество значений аргумента, то приведенные объявления не считаются перегруженными. f() можно определить как

void f(int i) { }

или как

void f(const int i) { }

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

// объявляются разные функцииvoid f(int*);void f(const int*); // и здесь объявляются разные функции
void f(int&);
void f(const int&);

Примеры работы с перегруженными функциями:

Пример № 1
Напишите функцию print_out, печатающую все целые числа в диапазоне от 1 до N. Проверьте работу функции, поместив ее в программу и передав ей число n – число, введенное с клавиатуры. Возвращаемый тип функции print_out должен быть void; функция не возвращает значение. Функция может быть вызвана простой инструкцией: print_out (n).

Исходный код:

#include<iostream.h>
#include<conio.h>
void print_out (int n) // void означает, что функция ничего не возвращает
{
clrscr ();
int i;
for (i=0;i<n;i++)
cout <<i<<"";
}
void main ()
{
int n;
cout<<"Vvedite N";
cin>>n;
print_out (n);
getch ();
}

 

Пример № 2
Напишите функцию, которая возвращает максимальное из двух целых чисел, полученных в качестве аргумента.

Исходный код (иногда называют "листинг"):

#include <iostream.h>
#include <conio.h>
int max_chislo(int n, int m)
{
if (m>n)
return m;
else return n;
}
void main ()
{
clrscr ();
int n;
int m;
cout <<"Vvedite m=";
cin>>m;
cout <<"Vvedite n=";
cin >>n;
cout<<max_chislo(m, n);
getch ();
}

 

Теория:
Примеры функций преобразования. Цель их использования.
1). atoi() преобразует строку в целое число
2). itoa() преобразует целое число в строку
3). atof() преобразует строку в вещественное число
4). fcvt() преобразует вещественное число в строку


Основные функции ввода, вывода.
1). В Си используются функции printf() и scanf()
1.1) printf() – выводит форматированный текст на консоль
1.2) scanf() – сканирует данные с клавиатуры и заполняет переменные по адресам

2). В Си++ используются объекты cout и cin
2.1) сout – для вывода на консоль используется оператор <<
2.2) cin – для чтения с клавиатуры используется оператор >>

Функции работы с файлами. Примеры.
1) В Си используются следующие функции:
1.1) fopen() – открывает файл в заданном режиме
1.2) fprintf() – записывает форматированную строку в файл
1.3) fscanf() – читает данные из файла
1.4) fclose() – закрывает файл

Пример использования:

#include <stdio.h>
int main()
{
FILE *pFile = fopen(“file.txt” “w”); //открыли для записи
fprintf(f, “This is text file”); //записали в файл строчку
fclose(pFile); //закрыли файл
return 0;
}

 

2) В Си++ используют следующие классы:
2.1) fstream – класс файлового ввода-вывода
2.2) ofstream – класс файлового вывода
2.3) ifstream – класс файлового ввода

В данных классах используют следующие методы:
* open() – открывает файл
* getline() – читает строку из файла
* write() – записывает строку в файл
* close() – закрывает файл

Также возможно использовать перегруженные операторы << и >> для записи в файл и чтения из файла.
Пример использования:

#include <iostream.h>
#include <fst



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2017-06-21 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: