Пользовательские типы данных в С++. Тема 2-6

Содержание

Слайд 2

Абстрагирование в программировании Абстрагирование – процесс рассмотрения чего-то независимо от его

Абстрагирование в программировании

Абстрагирование – процесс рассмотрения чего-то независимо от его

связей, свойств и конкретных особенностей
Абстрагирование — операция мышления, состоящая в отвлечении от несущественных сторон, свойств, связей объекта (предмета или явления) с целью выделения их существенных, закономерных признаков.
Результат абстрагирования — абстрактные понятия, например: цвет, кривизна, масса, красота и т. д.
Слайд 3

Абстрагирование в программировании: два пути Обобщение – процесс выделения только тех

Абстрагирование в программировании: два пути

Обобщение – процесс выделения только тех

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

Абстрагирование в программировании Алгоритмы Структуры данных Модули Классы Фреймворки, каркасы Функции

Абстрагирование в программировании

Алгоритмы
Структуры данных
Модули
Классы
Фреймворки, каркасы
Функции

Слайд 5

Композиция объектов Композиция объектов – комбинирование объектов и свойств (подобъектов) для

Композиция объектов

Композиция объектов – комбинирование объектов и свойств (подобъектов) для формирования

нового объекта
Три фундаментальных формы композиции:
Агрегация
Конкатенация
Делегирование
Эти формы не взаимоисключающие
Программирование – процесс композиции и декомпозиции
Слайд 6

Агрегация Агрегация – процесс формирования объекта из перечислимой коллекции подобъектов Агрегат

Агрегация

Агрегация – процесс формирования объекта из перечислимой коллекции подобъектов
Агрегат – это

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

Пример – символы в строку:
`a`, `b`, `c`, `d` -> “abcd”

Слайд 7

Конкатенация Конкатенация – объект формируется путём добавления новых свойств к существующему

Конкатенация

Конкатенация – объект формируется путём добавления новых свойств к существующему объекту
Конкатенация

– объект формируется путём добавления свойств других объектов
Каждый подобъект может потерять свою идентичность относительно своего происхождения
В случае именованных свойств может возникнуть коллизия с одинаковыми именами.

Пример – строки в строку:
“ab”, “cd” -> “abcd”

Слайд 8

Обсуждение по массивам 1, 2, 3, 4, 5 [1, 2, 3,

Обсуждение по массивам

1, 2, 3, 4, 5
[1, 2, 3, 4, 5

] – агрегация массива из чисел
Дано: [1, 2] и [3, 4] ? [ [1, 2] , [3, 4] ]
Вместо [i,j] правильно [i][j]
Слайд 9

Фабричные функции Фабричная функция – любая функция, которая возвращает новый объект

Фабричные функции

Фабричная функция – любая функция, которая возвращает новый объект
На самом

деле не любая, так как, например, в ООП есть специальная функция для создания объектов – конструктор и смешивать её с фабричными функциями не надо в целях избежания терминологической путаницы.
ConcatIntToArray: 1,2,3,4 => [1,2,3,4]
AggregateIntToArray: 1,2,3,4 => [1,2,3,4]
ConcatArrayFromArrays: [1,2,3],[4,5] =>[1,2,3,4,5]
AggregateArrayFromArrays:
[1,2,3],[4,5] =>[ [1,2,3], [4,5] ] – это двумерный массив, массив массивов
Слайд 10

При решении задач обработки большого количества однотипных данных используют массивы Чаще

При решении задач обработки большого количества однотипных данных используют массивы
Чаще встречаются

комбинации из данных разных типов: например, сведения о сотрудниках (фамилия, имя, год рождения, стаж работы)
Для обработки разнотипных данных в языке С++ имеется составной объект – структура

Структуры С++

Слайд 11

Структура – это составной объект, содержащий данные, объединенные в группу под

Структура – это составной объект, содержащий данные, объединенные в группу под

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

Структуры С++

Слайд 12

Объявление структурного типа выполняется в виде шаблона, общий формат которого: struct

Объявление структурного типа выполняется в виде шаблона, общий формат которого:
struct Имя_Типа

{
Описание полей
} ;
Структурный тип обычно декларируется в глобальной области, т.е. до первой выполняемой функции. Тогда его можно использовать во всех функциях, входящих в проект.

Структуры С++: объявление

Точка с запятой

Слайд 13

Обращение к полям структур выполняется с помощью составных имен, которые образуются

Обращение к полям структур выполняется с помощью составных имен, которые образуются

двумя способами:
1) при помощи операции принадлежности ( . ) от значения (имени структурной переменной) к полю:
Имя_Структуры . Имя_Поля
или
( *Указатель_Структуры ) . Имя_Поля
2) при помощи операции косвенной адресации ( –> ) от адреса к полю
Указатель_Структуры –> Имя_Поля
или
( &Имя_Структуры ) –> Имя_Поля

Структуры С++: обращения к подобъектам

Слайд 14

После введения типа структура можно задать переменные или массивы этого типа

После введения типа структура можно задать переменные или массивы этого типа
struct

Date
{
unsigned int Year;
char Month[12];
unsigned int Day;
char DayWeek[10];
}
int main()
{
Date D1 = new Date();
Date *ArDate = new Date[10];
}

Структуры С++: переменные типа структура

Слайд 15

Допускаются и другие варианты описания структурных переменных. Можно вообще не задавать

Допускаются и другие варианты описания структурных переменных. Можно вообще не задавать

имя типа, а описывать сразу переменные:
struct {char fam[30];
int kurs;
char grup[3];
float stip;
} studi, stud2, *pst;
В этом примере кроме двух переменных структурного типа объявлен указатель pst на такую структуру. В данном описании можно было задать имя структурного типа student.
Слайд 16

#include using namespace std; struct pixel { unsigned char red; unsigned

#include using namespace std; struct pixel { unsigned char red; unsigned char green;

unsigned char blue; };
int main(int argc, char *argv[]) { int i,j; // instantiations pixel pixela; pixel image[256][256]; ... return 0; }

Структуры С++: представление в памяти

Слайд 17

#include using namespace std; struct student { char name[80]; int id;

#include using namespace std;
struct student { char name[80]; int id; int major; };
int main(int argc, char

*argv[]) { int i,j; // instantiations student s1; ... return 0; }

Структуры С++: представление в памяти

Слайд 18

Структуры С++: инициализация Элементы структуры в памяти запоминаются последовательно, в том

Структуры С++: инициализация

Элементы структуры в памяти запоминаются последовательно, в том порядке,

в котором они объявляются: первому элементу соответствует меньший адрес памяти, последнему - больший
Слайд 19

… int main(int argc, char *argv[]) { student s1,s2; strncpy(s1.name,”Bill”,80); s1.id


int main(int argc, char *argv[]) {
student s1,s2;
strncpy(s1.name,”Bill”,80);
s1.id = 5;

s1.major = CECS;
s2 = s1;
return 0; }

Структуры С++: присваивание

При присваивании происходит полное копирование

Слайд 20

Элементом структуры может быть другая структура. struct myfile { char name[10];

Элементом структуры может быть другая структура.
struct myfile {
char name[10];
char ftype[4];
int ver;
};
struct

dir {
struct myfile f;
int size;
} my_f [100];
Шаблон для вложенной структуры должен располагаться перед определением фактической структурной переменной в рамках другой структуры.
my_f [0].size //элемент size 1-ой структуры
my_f [2].f.ver //элемент ver вложенной структуры f в 3-й структуре my_f

Структуры С++: вложенность

Слайд 21

Для передачи информации о структуре внутрь функции используются следующие способы: Использование

Для передачи информации о структуре внутрь функции
используются следующие способы:
Использование в

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

Структуры С++: использование в функциях

Слайд 22

Структуры С++: битовые поля Битовые поля применяются для экономного хранения данных

Структуры С++: битовые поля

Битовые поля применяются для экономного хранения данных малого

диапазона, а также для работы с данными, в которых отдельные биты имеют самостоятельное значение.
Битовое поле может быть объявлено только как элемент структуры.
Цепочка битов не должна превышать машинного слова.
/*контрольный байт*/
struct bit_area
{
unsigned char er : 1; //бит ошибки
unsigned char rd : 1; //бит готовности
unsigned char dat : 6; //поле данных
}cntrl_byte;

Двоеточие

Слайд 23

Слайд 24

В классе n учеников. Введите фамилии и оценки по 5 предметам

В классе n учеников. Введите фамилии и оценки по 5 предметам

для каждого ученика, найдите средний балл и выведите на экран фамилию и средний балл лучшего ученика.

#include
#include
using namespace std;
int main()
{
SetConsoleCP(1251); // установка кодовой страницы win-cp 1251 в поток ввода
SetConsoleOutputCP(1251); // установка кодовой страницы win-cp 1251 в поток вывода
struct Student
{
string fam;
int p1, p2, p3, p4, p5;
float sr;
};
int n, i;

Пример со структурой в С++

Слайд 25

cin>>n; Student a[n]; float m_b=0; for(i = 0;i { cout cin

cin>>n;
Student a[n];
float m_b=0;
for(i = 0;i < n;

i++)
{
cout << "Введите фамилию" << endl;
cin >> a[i].fam;
cout << "Введите 5 оценок" << endl;
cin >> a[i].p1 >> a[i].p2 >> a[i].p3 >> a[i].p4 >> a[i].p5;
a[i].sr = (a[i].p1+ a[i].p2 + a[i].p3 + a[i].p4 + a[i].p5) / 5.;
}
for(i = 0; i < n; i++)
if(a[i].sr >= m_b) m_b = a[i].sr;
for(i = 0; i < n; i++)
if (a[i].sr == m_b)
cout << a[i].fam << " средний балл= « << a[i].sr << endl;
return 0;
}

продолжение программы:

Пример со структурой в С++: экран

Слайд 26

Пример со структурой в С++: запись в файл Используем также как

Пример со структурой в С++: запись в файл

Используем также как другие

потоки, например, стандартный поток вывода cout

о – значит out, т.е. выходной поток

ofstream f;
f.open(“out.txt”);
f<f.close();

struct base
{
string name;
string work;
int year;
};
base a;

Открыли и закрыли файловый поток

Слайд 27

#include #include #include using namespace std; struct base { string name;

#include
#include
#include
using namespace std;
struct base
{
string name;

string work;
int year;
};
int main()
{SetConsoleCP(1251);
SetConsoleOutputCP(1251);
int n; //кол-во экземпляров структуры//
cin>>n;
base b[n];

for (int i=0;i {
cout << "Enter name :" << endl;
cin >> b[i].name;
cout << "Enter work :" << endl;
cin >> b[i].work;
cout << "Enter year :" << endl;
cin >> b[i].year;
}
ofstream outfile;
outfile.open(“out.txt");
for (int i = 0; i < n; ++i)
outfile << b[i].name << " " << b[i].work << " " << b[i].year << endl;
outfile.close();
return 0;
}

продолжение программы

Пример со структурой в С++: запись в файл

Слайд 28

struct base { string name; string work; int year; }; base

struct base
{
string name;
string work;
int year;
};
base a;
ifstream

f;
f.open(“out.txt”);
f>>a.name>>a.work>>a.year;
f.close()

Пример со структурой в С++: чтение из файла

i – значит in, т.е. входной поток

Все операции аналогичны стандартным потокам

Слайд 29

Перечисляемый тип С++ Используется для объявления набора поименованных целых констант. Формат:

Перечисляемый тип С++

Используется для объявления набора поименованных целых констант.
Формат:
enum {<Ид>[=<Целое>] [,<Ид>[<>]…]}


<Список переменных>;
Пример:
enum {SUN, MON, TUES, FRI=5, SAT} day;
Константы присваиваются, начиная с нуля или с указанного значения.

Имя
переменной

SUN =0, MON = 1, TUES = 2, FRI=5, SAT=6

Слайд 30

Псевдонимы typedef ; Примеры: 1) typedef unsigned int word; 2) typedef

Псевдонимы


typedef <Описание типа> <Имя объявляемого типа>;
Примеры:
1) typedef unsigned int word;


2) typedef enum {False, True} boolean;

Имя
нового типа

Слайд 31

Слайд 32

Любая функция имеет физическое местоположение в памяти. Адрес функции является входной

Любая функция имеет физическое местоположение в памяти.
Адрес функции является входной точкой

в тело функции.
Этот адрес может быть присвоен указателю.
Следовательно, указатель на функцию может быть использован для вызова функции.
В общем виде указатель на функцию определяется следующим образом:
тип функции (*имя указателя функции)(список параметров);
Например, int (*fprt)(int);
Определяется указатель fprt, на функцию с целочисленным параметром, возвращающую целочисленное значение.

Указатель на функцию

Слайд 33

Определим функцию f1, вычисляющую сумму двух чисел, и функцию f2, вычисляющую

Определим функцию f1, вычисляющую сумму двух чисел, и функцию f2, вычисляющую

разность этих же чисел.
double SUM (double a, double b)
{
return a + b;
}
double RAZ (double a, double b)
{
return a - b;
}
void main ( )
{
double q =-44, w = 70;
double d;
double (*ptr_f) (double, double); /* объявили указатель на функцию*/
ptr_f = SUM; /* ptr_f присвоили адрес SUM */
d = (*ptr_f) (q, w); /* вызвали SUM по адресу */
ptr_f = RAZ; /* присвоили адрес RAZ */
d = (*ptr_f) (q, w); /* вызвали RAZ */
}

Указатель на функцию: пример

Слайд 34

. . . double ff(double a ,double b, double (*f)(double,double)) {

. . .
double ff(double a ,double b, double (*f)(double,double))
{
return f(a,b);
}
int

main()
{
double (*f_p)(double, double);
. . .
cout<cout< cout<

Указатель на функцию: параметром для некоторой функции

Слайд 35

Делегирование Делегирование – объект перенаправляет (или делегирует) к другому объекту, который

Делегирование

Делегирование – объект перенаправляет (или делегирует) к другому объекту, который действует

от его имени.
Делегирование – механизм совместного использования кода и данных между объектами
Делегирование – создание элемента одного объекта в контексте другого.
Слайд 36

Для задания имени указателя для наглядности используйте using using validateFcn =

Для задания имени указателя для наглядности используйте using
using validateFcn =

bool(*)(int, int);
Далее рассмотрите пример в файле Сквозной пример III (на сайте курса)

Указатель на функцию, псевдоноимы и сквозной пример с обработкой корректностью ввода

Слайд 37

Слайд 38

Зачем вообще может понадобится? Например, такая проблема… «Чистые» функции – данные

Зачем вообще может понадобится? Например, такая проблема…
«Чистые» функции – данные программы

копируются в данные функции.
Изменение состояния происходит через возвращаемое значение в вызывающей функции.
Данные между вызовами функций не сохраняются
Если использовать указатели и ссылки, то можно изменить данные переданных через такие параметры.

Композиция данных и функций.

Слайд 39

Часть данных, которые нужно изменять сгруппировать для удобства Data{D_1; D_2;}; int

Часть данных, которые нужно изменять сгруппировать для удобства
Data{D_1; D_2;};
int F_1 (int x,float

y, char z, ссылка на экземпляр Data)
int F_1 (int a,int b, ссылка на экземпляр Data)
Тем не менее программисту надо будет постоянно следить, чтобы не появились (или не забылись) какие-то функции, изменяющие данные, т.е. проблема совместного использования данных

Композиция данных и функций

Слайд 40

Идея: сгруппировать функции и связать их с данными так, чтобы только

Идея: сгруппировать функции и связать их с данными так, чтобы только

функции из этой композиции могли изменять данные
Composition(A+D) -> Methods {
int F_1 (int x,float y, char z, ссылка на экземпляр Data), int F_1 (int a,int b, ссылка на экземпляр Data), экземпляр Data }

Композиция данных и функций

Слайд 41

Дополнительные идеи для реализации в языке: Для удобства не передавать каждый

Дополнительные идеи для реализации в языке:
Для удобства не передавать каждый раз

ссылку на экземпляр
Делегирование исполнения:
M_1(int x,float y, char z)= { F_1(int x,float y, char z, Data& theData }
Как-то ограничить область действия данных только этой композицией

Композиция данных и функций

Слайд 42

Композиция данных и функций: реализация структуры с функциями в С++ struct

Композиция данных и функций:
реализация структуры с функциями в С++

struct Number
{

int ch;
nm sum(nm a)
{ nm rez; rez.ch = a.ch + ch; return rez;}
nm sub(nm a)
{ nm rez; rez.ch = ch - a.ch;return rez;}
nm mult(nm a)
{ nm rez; rez.ch = ch * a.ch; return rez;}
nm divv(nm a)
{ nm rez; rez.ch = ch / a.ch; return rez;}
};
Слайд 43

Композиция данных и функций: идея реализации struct Number { int ch;

Композиция данных и функций:
идея реализации

struct Number
{
int ch;
Number sum(Number

a)
{ Number rez; rez.ch = a.ch + ch; return rez;}
};

struct Number
{
int ch;
Number sum(Number* this, nm a)
{Number rez; rez.ch = a.ch + this->ch; return rez;}
};

Написанный Вами код

Код сгенерированный компилятором

Специальное ключевое слово для обращения к полям ЭТОЙ структуры

Слайд 44

Композиция данных и функций: использование структуры «Число» int main() { //создаём

Композиция данных и функций:
использование структуры «Число»

int main()
{
//создаём числа в автоматической

памяти
Number x = { 1 };//иницализатор как для массивов
Number y ;
y.ch = 2;
cout <<"sum = " <cout <<"x = " <//создаём числа в динаимческой памяти
Number* px, *py, z;
px = new Number({1});
py = new Number();
py->ch = 2;
z = px->sum(*py);
cout << "z = " <//удаляем числа из динаимческой памяти
delete px,
delete py;
}
Слайд 45

Композиция данных и функций: структура Если несколько "связанных" данных? Компилятор сам

Композиция данных и функций: структура

Если несколько "связанных" данных?
Компилятор сам

создаёт структуру, в которую включает (осуществляет композицию) всех связанные данных, т.е. сводим задачу к предыдущей и получаем "замыкание".
Активно используется в JavaScipt
В С++ такая возможность реализована в лямбда выражениях (о них в другой лекции)
Слайд 46

Слайд 47

Сигнатура функции – определяет правила использования функции. Обычно сигнатура представляет собой

Сигнатура функции – определяет правила использования функции. Обычно сигнатура представляет собой

описание функции.
до этого использовали понятие интерфейс
Семантика функции – определяет способ реализации функции. Обычно представляет собой тело функции.
до этого использовали понятие реализация

Сигнатура

Слайд 48

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

Перегрузка функций: постановка проблемы

Задача:
Реализовать набор функций, реализующих один и тот же

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

Перегрузка функций: примеры int Square(int arg) {return arg*arg;} double Square(double arg)

Перегрузка функций: примеры

int Square(int arg)
{return arg*arg;}
double Square(double arg)
{return arg*arg;}
char

*Square(const char *arg, int n)
{
static char res[256];
int j = 0;
while (*arg && j < n)
{
if (*arg != ' ') res[j++] = *arg;
res[j++] = *arg++;
}
res[j] = 0;
return res;
}
Слайд 50

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

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

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

Перегрузка функций: о компиляторе

Слайд 51

Декорирование имен – формирование уникального внутреннего имени функции. void Func(void); //

Декорирование имен – формирование уникального внутреннего имени функции.
void Func(void); //

@Func$qv
void Func(int); // @Func$qi
void Func(int, int); // @Func$qii
void Func(char*); // @Func$qpc
void Func(unsigned); // @Func$qui
void Func(const char*); // @Func$qpxc

Перегрузка функций: идея для компилятора

Слайд 52

Если точного соответствия не найдено, выполняются продвижения порядковых типов в соответствии

Если точного соответствия не найдено, выполняются продвижения порядковых типов в соответствии

с общими правилами преобразования типов: bool → int, char → int, float → double и т. п.
Далее выполняются стандартные преобразования типов, например, int → double или указателей в void*.
Далее выполняются преобразования типа, заданные пользователем, а также поиск соответствий за счет переменного числа аргументов функций.
Если соответствие на одном и том же этапе может быть получено более чем одним способом, вызов считается неоднозначным и выдается сообщение об ошибке.

Перегрузка функций: поиск вариантов

Слайд 53

Перегрузка функций: неоднозначность Неоднозначность может появиться при: 1. Преобразовании типа; 2.

Перегрузка функций: неоднозначность

Неоднозначность может появиться при:
1. Преобразовании типа;
2. Использовании параметров-ссылок;
3. Использовании

аргументов по умолчанию.

Правила описания перегруженных функций:
1. Нельзя перегружать функции, отличающиеся только типом возвращаемого значения
2. Функции не могут быть перегружены, если описание их параметров отличается только модификаторами const, volatile или использованием ссылки (например, int и const int или int и int&)

Слайд 54

Перегрузка функций: ошибки int Sum(int x, int y) { return x

Перегрузка функций: ошибки

int Sum(int x, int y)
{
    return x + y;
}
int Sum(int

number1, int number2)
{
    return x + y;
}
void Sum(int x, int y)
{
    Console.WriteLine(x + y);
}

Сигнатура у всех этих функций будет совпадать:
Sum(int, int)

Слайд 55

Перегрузка функций: дополнительные особенности Перегруженные функции должны находиться в одной области

Перегрузка функций:
дополнительные особенности

Перегруженные функции должны находиться в одной области видимости,

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

Перегрузка функций: особенности C++ Константные ссылки: возможно: int& и const int&

Перегрузка функций: особенности C++

Константные ссылки: возможно: int& и const int&

void Func(const

long& a) {
// a++;
cout << sizeof(a); cout << "\t non const";
}
void Func(long& a) {
a++;
cout << sizeof(a); cout << "\t const";
}
int main(int argc, char* argv[]) {
const long xc = 1; long x = 1;
Func(x); cout << endl;
Func(xc); cout << endl;
cout << x << "\t" << xc;
return 0; }
Слайд 57

Для передачи типов значений по ссылке в С# были введены специальные

Для передачи типов значений по ссылке в С# были введены специальные

ключевые слова out и ref, которые учитываются как значимые при перегрузке

Перегрузка функций: другие ЯВУ (С#)

void Increment(int val)
{
    val++;
    Console.WriteLine(val);
}
void Increment(ref int val)
{
    val++;
    Console.WriteLine(val);
}
void Increment(out int val)
{
    val++;
    Console.WriteLine(val);
}

ref указывает компилятору, что передаваемый объект был инициализирован до вызова функции

out сообщает, что переменная будет инициализирована внутри функции

Слайд 58

Перегрузка функций – это разновидность статического полиморфизма, при которой вопрос о

Перегрузка функций – это разновидность статического полиморфизма, при которой вопрос о

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

Перегрузка функций: выводы

Слайд 59

Слайд 60

Функция main Функция main – та функция, с запуска которой начинает

Функция main

Функция main – та функция, с запуска которой начинает работу

консольное приложение, написанное на C++.
Форматы функции main:
void main(void);
int main(void);
void main(int argc, char *argv[]);
int main(int argc, char *argv[]);
// указаны традиционные имена для параметров
Первый и третий варианты не являются стандартными и не работают на некоторых платформах. Кроме того, писать void в скобках не обязательно. Таким образом, самое простое и легальное объявление функции main int main();
Слайд 61

Передача параметров в функцию main Наличие параметров позволяет передать в запускаемую

Передача параметров в функцию main

Наличие параметров позволяет передать в запускаемую программу

данные командной строки: пользователь может при запуске программы указать несколько дополнительных параметров, разделяя их пробелами.
int main(int argc, char *argv[]);
Аргумент argc определяет, сколько параметров, включая имя программы, записано в командной строке. Массив нуль-терминированных строк argv хранит значение каждого параметра (argv[0] – имя exe-файла с полным путем к нему, argv[1] – первый параметр и т.д.).
Слайд 62

Пример передачи параметров в функцию main Задача: в программу в качестве

Пример передачи параметров в функцию main

Задача: в программу в качестве параметра

передаётся имя файла для обработки. Если параметр не передан, программа должна запросить имя файла в диалоге.
int main(int argc, char *argv[]) {
char FileName[40];
setlocale(LC_ALL, ”.1251”);
if (argc>2) {
cout << ”Слишком много параметров\n”;
return 1;
}
if (argc==1) {
cout << ”Введите имя обрабатываемого файла: \n”;
cin.getline(FileName, 40);
}
else
strcpy(FileName, argv[1]);

}
Слайд 63

Слайд 64

Слайд 65

Перегрузка операции вызова функции Запись: тип_возврата operator() (формальные параметры); Структура, в

Перегрузка операции вызова функции

Запись:
тип_возврата operator() (формальные параметры);
Структура, в которой определён

хотя бы один оператор вызова функции, называется функциональным классом. Функциональный класс может не иметь других полей и методов.
Функциональные классы используются в алгоритмах из библиотеки STL.
Слайд 66

Сквозной пример V

Сквозной пример V

Слайд 67

Работа с файлами и json https://www.youtube.com/watch?v=x8wsONn1IcQ

Работа с файлами и json
https://www.youtube.com/watch?v=x8wsONn1IcQ

Слайд 68

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

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

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

Перегрузка функций

Слайд 69

Слайд 70

Слайд 71

ШАБЛОНЫ ФУНКЦИЙ Многие алгоритмы не зависят от типов данных, с которыми

ШАБЛОНЫ ФУНКЦИЙ

Многие алгоритмы не зависят от типов данных, с которыми

они работают (классический пример — сортировка).
В С++ есть мощное средство параметризации — шаблоны.
С помощью шаблона функции можно определить алгоритм, который будет применяться к данным различных типов, а конкретный тип данных передается функции в виде параметра на этапе компиляции.
Слайд 72

ШАБЛОНЫ ФУНКЦИЙ Компилятор автоматически генерирует правильный код, соответствующий переданному типу. Таким

ШАБЛОНЫ ФУНКЦИЙ

Компилятор автоматически генерирует правильный код, соответствующий переданному типу.
Таким

образом, создается функция, которая автоматически перегружает сама себя и при этом не содержит накладных расходов, связанных с параметризацией.
template < typename T >
void sort( T array[], int size ); { /* тело функции */ }
Слайд 73

ШАБЛОНЫ ФУНКЦИЙ Первый же вызов функции, который использует конкретный тип данных,

ШАБЛОНЫ ФУНКЦИЙ

Первый же вызов функции, который использует конкретный тип данных,

приводит к созданию компилятором кода для соответствующей версии функции. Этот процесс называется инстанцированием шаблона (instantiation).
Конкретный тип для инстанцирования либо определяется компилятором автоматически, исходя из типов параметров при вызове функции, либо задается явным образом.
При повторном вызове с тем же типом данных код заново не генерируется.
Слайд 74

ШАБЛОНЫ ФУНКЦИЙ // шаблон функции определения минимума template T min( T

ШАБЛОНЫ ФУНКЦИЙ

// шаблон функции определения минимума
template < typename T >


T min( T a, T b )
{ return a < b ? a : b; }
// вызов функции по имени:
min( 1, 2 );
min( 'a', 'b' );
min( string( "abc" ), string( "cde" ) );
Слайд 75

ШАБЛОНЫ ФУНКЦИЙ int i[5] = { 5, 4, 3, 2, 1

ШАБЛОНЫ ФУНКЦИЙ

int i[5] = { 5, 4, 3, 2, 1

};
sort( i, 5 );
char c[] = "бвгда";
sort( c, strlen( c ) );
sort( c, 5 ); // ошибка!
Слайд 76

ШАБЛОНЫ ФУНКЦИЙ template char* read() { char *Buffer = new char[

ШАБЛОНЫ ФУНКЦИЙ

template< int BufferSize >
char* read()
{ char *Buffer =

new char[ BufferSize ];
/* считывание данных */
return Buffer; }
char *ReadString = read< 20 >();
delete [] ReadString;
ReadString = read< 30 >();
Слайд 77

ШАБЛОНЫ ФУНКЦИЙ // выведение значений параметров int i[5] = { 5,

ШАБЛОНЫ ФУНКЦИЙ

// выведение значений параметров
int i[5] = { 5, 4,

3, 2, 1 };
sort( i, i + 5 ); // вызывается sort< int >
char c[] = "бвгда";
sort( c, c + strlen( c ) ); // вызывается sort< char >
Слайд 78

ОБЪЕДИНЕНИЯ Объединения очень похожи на структуры, однако способ, с помощью которого

ОБЪЕДИНЕНИЯ

Объединения очень похожи на структуры, однако способ, с помощью которого C++

хранит объединения, отличается от способа, с помощью которого C++ хранит структуры.
union — это пользовательский тип, в котором все члены используют одну область памяти.
Это означает, что в любой момент времени объединение не может содержать больше одного объекта из списка своих членов.
Независимо от количества членов объединения, оно использует лишь количество памяти, необходимое для хранения своего крупнейшего члена.
Объединение состоит из частей, называемых элементами (членами).
Объединения могут быть полезны для экономии памяти при наличии множества объектов и/или ограниченном количестве памяти. Однако для их правильного использования требуется повышенное внимание, поскольку нужно всегда сохранять уверенность, что используется последний записанный элемент.
Слайд 79

Слайд 80

Слайд 81

Внутри программ объединения C++ очень похожи на структуры. Например, следующая структура

Внутри программ объединения C++ очень похожи на структуры. Например, следующая структура

определяет объединение с именем distance, содержащее два элемента:

union distance
{ int miles; long meters; };

Как и в случае со структурой, описание объединения не распределяет память. Вместо этого описание предоставляет шаблон для будущего объявления переменных.

Слайд 82

Следующая программа иллюстрирует использование объединения distance. Сначала программа присваивает значение элементу

Следующая программа иллюстрирует использование объединения distance. Сначала программа присваивает значение элементу
miles

и выводит это значение. Затем программа присваивает значение элементу meters. При этом значение элемента miles теряется:

#include
void main(void)
{ union distance
{ int miles; long meters; } walk;
walk.miles = 5; cout << «Пройденное расстояние в милях » << walk.miles << endl; walk.meters = 10000; cout << «Пройденное расстояние в метрах » << walk.meters << endl; }

Программа обращается к элементам объединения с помощью точки, аналогичная запись использовалась при обращении к элементам структуры

Слайд 83

Слайд 84

Использование объединений позволяет экономит память:

Использование объединений позволяет экономит память:

Слайд 85

Объединение хранит значение только одного элемента в каждый момент времени Объединение

Объединение хранит значение только одного элемента в каждый момент времени
Объединение представляет

собой структуру данных, которая, подобно структуре C++, позволяет вашим программам хранить связанные части информации внутри одной переменной. Однако в отличие от структуры объединение хранит значение только одного элемента в каждый момент времени. Другими словами, когда вы присваиваете значение элементу объединения, вы перезаписываете любое предыдущее присваивание.
Объединение определяет шаблон, с помощью которого ваши программы могут позднее объявлять переменные. Когда компилятор C++ встречает определение объединения, он распределяет количество памяти, достаточное для хранения только самого большого элемента объединения.
Слайд 86

Правила вычисления выражений Для выполнения операций над некоторыми типами данных требуется

Правила вычисления выражений

Для выполнения операций над некоторыми типами данных требуется

явное переопределение типов.
Различают:
Функциональное преобразование
<имя типа> (Список выражений)
Примеры:
int(3.14); float(2/3); int(‘A’);
Однако, функциональная запись не подходит для сложного типа.
В этом случае применяется каноническая форма преобразования:
(имя типа)<выражение>
Примеры:
(unsigned long)(x/3+2); (long)25;(char)123;
Если ввести новый тип – тогда можно использовать и функциональное преобразование
typedef unsigned long int uli;
uli(x/3-123);