initial commit
This commit is contained in:
		
						commit
						2369f801af
					
				
					 76 changed files with 4273 additions and 0 deletions
				
			
		
							
								
								
									
										60
									
								
								seminar01_overload/classroom_tasks/code/01ref/00ref.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								seminar01_overload/classroom_tasks/code/01ref/00ref.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     В C++ вводится понятие нового типа под названием Ссылка | ||||
|      | ||||
|     Ссылку можно рассматривать как новое имя для объекта. | ||||
|     Ссылку также можно рассматривать как удобный указатель, который автоматически разыменовывается | ||||
|     (На самом деле под капотом ссылка и является указателем) | ||||
| 
 | ||||
|     Ссылка объявляется с помощью значка & после имени типа. | ||||
|     Не стоит путать & используемый при объявлении ссылки с & используемым для нахождения адреса переменной.  | ||||
|     Это разные & | ||||
|      | ||||
|      | ||||
|     Пусть есть переменная a | ||||
|     int a = 10; | ||||
|     Давайте создадим указатель и ссылку на эту переменную и увеличим её на 1 с помощью указателя/ссылки | ||||
|      | ||||
|     Используем указатель:               Используем ссылку: | ||||
|     int* p = &a;                        int& r = a; | ||||
|     *p += 1;                            r += 1; | ||||
| 
 | ||||
| 
 | ||||
|     Ссылкой пользоваться удобно, так как: | ||||
| 
 | ||||
|     1)  При создании ссылки нам не нужно передавать ей адрес | ||||
|         Просто передаём ей саму переменную, а ссылка уже сама находит её адрес | ||||
| 
 | ||||
|     2)  Не нужно её разыменовывать, она всегда разыменовывается сама | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a = 10; | ||||
|      | ||||
|     int& r = a; | ||||
|     r += 1; | ||||
| 
 | ||||
|     cout << a << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|     1)  Используйте ссылку r, чтобы увеличить a в 2 раза | ||||
|         Проверьте, как изменилась a, напечатав её | ||||
| 
 | ||||
| 
 | ||||
|     2)  Используйте ссылку r, чтобы присвоить a число 100 | ||||
|         Проверьте, как изменилась a, напечатав её | ||||
| 
 | ||||
| 
 | ||||
|     3)  Создайте переменную b типа float, равную 1.5 | ||||
|         Создайте ссылку на b и используйте эту ссылку, чтобы возвести b в квадрат | ||||
| 
 | ||||
| */ | ||||
							
								
								
									
										39
									
								
								seminar01_overload/classroom_tasks/code/01ref/01ref.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								seminar01_overload/classroom_tasks/code/01ref/01ref.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Пусть у нас есть некоторый объект, например | ||||
|         int a = 10; | ||||
| 
 | ||||
|     После того как мы создали ссылку на этот объект | ||||
|         int& r = a; | ||||
| 
 | ||||
|     Все (почти) операции применяемые к ссылке r применяются на самом деле к объекту a | ||||
|     Как будто у одного объекта теперь два имени a и r | ||||
|     Поэтому можно сказать, что ссылка это новое имя для объекта | ||||
| 
 | ||||
|     При этом изменить саму ссылку (например, чтобы она начала указывать на другое имя) нельзя | ||||
| */ | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a = 10; | ||||
|     int& r = a; | ||||
| 
 | ||||
| 
 | ||||
|     r += 5;                     // Прибавим к a число 5
 | ||||
|     r *= 2;                     // Умножим a на 2
 | ||||
|     cout << r << endl;          // Напечатаем a
 | ||||
|     cout << sizeof(r) << endl;  // Напечатаем размер a
 | ||||
|     cout << &r << endl;         // Напечатаем адрес a
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|     1)  Чему будет равно значение a в конце этой программы | ||||
| 
 | ||||
| 
 | ||||
| */ | ||||
							
								
								
									
										43
									
								
								seminar01_overload/classroom_tasks/code/01ref/02ref.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								seminar01_overload/classroom_tasks/code/01ref/02ref.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Пусть у нас есть некоторый объект, например | ||||
|         int a = 10; | ||||
| 
 | ||||
|     После того как мы создали ссылку на этот объект | ||||
|         int& r = a; | ||||
| 
 | ||||
|     Все (почти) операции применяемые к ссылке r применяются на самом деле к объекту a | ||||
|     Как будто у одного объекта теперь два имени a и r | ||||
|     Поэтому можно сказать, что ссылка это новое имя для объекта | ||||
| 
 | ||||
|     При этом изменить саму ссылку (например, чтобы она начала указывать на другое имя) нельзя | ||||
| */ | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a[5] = {10, 20, 30, 40, 50}; | ||||
| 
 | ||||
|     int& b = a[1]; | ||||
|     b += 1; | ||||
| 
 | ||||
|     for (int i = 0; i < 5; ++i) | ||||
|     { | ||||
|         cout << a[i] << " "; | ||||
|     } | ||||
|     cout << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|     1)  Что будет содержать массив a в конце данной программы? | ||||
| 
 | ||||
|     2)  Создайте ссылку, которая будет указывать на последний элемент массива a | ||||
|         Используйте эту ссылку, чтобы умножить последний элемент массива на 2 | ||||
|         Напечатайте этот массив | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,49 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Несмотря на то, что ссылки и указатели во многом похожи, у них есть и много больших отличий. | ||||
|     (помимо разной инициализации и того, что ссылку не нужно постоянно разыменовывать) | ||||
| 
 | ||||
| 
 | ||||
|     Различие 1)   | ||||
|         Указатель можно создать без инициализации вот так: | ||||
|             int* p; | ||||
|         В этом случае в p будет храниться произвольный адрес. | ||||
|         Разыменовывать такой указатель, не задав его значение адресом какого-либо объекта, | ||||
|         очень опасно, это может привести к сложновыявляемым ошибкам. | ||||
| 
 | ||||
|         Ссылку нельзя создать без инициализации, то есть так нельзя: | ||||
|             int& r; | ||||
|         При создании ссылки нужно указать на что она будет указывать | ||||
| 
 | ||||
| 
 | ||||
|     Различие 2)   | ||||
|         Указатель можно приравнять нулевому значению | ||||
|         В C++ вводится специальное нулевое значение для указателя nullptr | ||||
|         Вместо NULL, который был просто равен числу 0. В C++ лучше использовать nullptr | ||||
|         Разыменование нулевого указателя также приведёт к ошибке. | ||||
| 
 | ||||
|         Ссылку нельзя присвоить никакому нулевому значению | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|     1)  Попробуйте создать: | ||||
|         a)  Указатель без инициализации | ||||
|         б)  Ссылку без инициализации | ||||
| 
 | ||||
|         в)  Указатель, равнуй нулевому значению nullptr | ||||
|         г)  Ссылку, равную нулю | ||||
|      | ||||
|         Скомпилируется ли программа в этих 4-х случаях? | ||||
| */ | ||||
|  | @ -0,0 +1,52 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Несмотря на то, что ссылки и указатели во многом похожи, у них есть и много больших отличий. | ||||
|     (помимо разной инициализации и того, что ссылку не нужно постоянно разыменовывать) | ||||
| 
 | ||||
|      | ||||
|     Различие 3)  Указатель можно переприсвоить. Если указатель сначала указывал в одно место, | ||||
|         например, на переменную a, то можно просто написать | ||||
|             p = &b; | ||||
|         и указатель станет указывать на переменную b. | ||||
| 
 | ||||
|         Со ссылками такое не пройдёт, они всегда указывают на тот объект, который был указан при создании ссылки | ||||
|         При попытке изменить это и написать что-то вроде | ||||
|             r = b; | ||||
|         ссылка автоматически разыменуется и присваивание произойдёт к тому, на что указывала ссылка | ||||
| 
 | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a = 10; | ||||
|     int b = 20; | ||||
| 
 | ||||
|     int* p = &a; | ||||
|     *p += 1; | ||||
|     p = &b; | ||||
|     *p += 1; | ||||
| 
 | ||||
|     cout << a << " " << b << endl; | ||||
| 
 | ||||
| 
 | ||||
|     int& r = a; | ||||
|     r += 1; | ||||
|     r = b; | ||||
|     r += 1; | ||||
| 
 | ||||
|     cout << a << " " << b << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|     1)  Попробуйте понять, что напечатает программа без её запуска | ||||
| 
 | ||||
|     2)  Запустите программу, проверьте ваши догадки и объясните результат | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,44 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Несмотря на то, что ссылки и указатели во многом похожи, у них есть и много больших отличий. | ||||
|     (помимо разной инициализации и того, что ссылку не нужно постоянно разыменовывать) | ||||
| 
 | ||||
|     Различие 4)   | ||||
|         Арифметика указателей.  | ||||
|         К указателю можно прибавлять/отнимать целые числа. Можно вычесть 2 указателя. | ||||
|         Можно применить [] к указателю. При всём этом, желательно, чтобы указатель указывал на элемент массива. | ||||
|         Неаккуратное использование арифметики указателей может привести к ошибкам. | ||||
|         Например, можно прибавить к указателю не то число и выйти за пределы массива. | ||||
|          | ||||
| 
 | ||||
|         Ничего такого со ссылками сделать нельзя. | ||||
|         При попытке прибавить к ссылке число, оно прибавится к той переменной, на которую указывает ссылка. | ||||
|         Так как ссылка автоматически разыменуется. | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a[5] = {10, 20, 30, 40, 50}; | ||||
|      | ||||
|     int* p = &a[0]; | ||||
| 
 | ||||
|     p += 1;     // Увеличиваем указатель
 | ||||
|     *p += 1;    // Увеличиваем то, на что указывает указатель
 | ||||
| 
 | ||||
| 
 | ||||
|     int& r = a[0]; | ||||
| 
 | ||||
|     r += 1;     // Увеличиваем то, на что указывает ссылка (она автоматически разыменовывается)
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|     1)  Чему будет равен массив a в конце данной программы | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,46 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Несмотря на то, что ссылки и указатели во многом похожи, у них есть и много больших отличий. | ||||
| 
 | ||||
|     Различие 5)   | ||||
|         Ссылки это не совсем обычный объект, некоторые операции с ними запрещены: | ||||
|          | ||||
|         Ссылку нельзя сделать элементом массива | ||||
| 
 | ||||
|         Нельзя получить адрес ссылки (если применим & то вернётся адрес того объекта на который указывет ссылка) | ||||
|         Нельзя создать укатель на ссылку | ||||
|         Нельзя создать ссылку на ссылку | ||||
| */ | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
| 
 | ||||
|     int x = 1; | ||||
|     int y = 2; | ||||
|     int z = 2; | ||||
| 
 | ||||
|     int& a[3] = {x, y, z};  // Ошибка, создать массив из ссылок не получится
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|     1)  Можно ли инициализировать ссылку на int простым числом вот так: | ||||
|             int& r = 5; | ||||
| 
 | ||||
| 
 | ||||
|     2)  Ссылку на ссылку создать нельзя, но код ниже почему-то работает. | ||||
|         Объясните почему этот код работает | ||||
|              | ||||
|             int a = 10; | ||||
|             int& r1 = a; | ||||
|             int& r2 = r1; | ||||
| 
 | ||||
|             r2 += 1; | ||||
| 
 | ||||
| */ | ||||
							
								
								
									
										69
									
								
								seminar01_overload/classroom_tasks/code/01ref/07func_ref.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								seminar01_overload/classroom_tasks/code/01ref/07func_ref.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,69 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     В 90% случаях ссылки используются для того чтобы передать что либо в функцию | ||||
|     Часто нам хочется передать переменную в функцию и изменить её там (внутри функции) | ||||
|     Это можно делать и с помощью указателей, но с помощью ссылок это делать гораздо удобней | ||||
|     Рассмотрим два эквивалентных участка кода: | ||||
| 
 | ||||
|     Передаём по указателю:                    Передаём по ссылке: | ||||
| 
 | ||||
|     void sqr(int* p)                          void sqr(int& r) | ||||
|     {                                         { | ||||
|         *p = *p * *p;                             r = r * r; | ||||
|     }                                         } | ||||
|                                            | ||||
|     int main()                                int main()  | ||||
|     {                                         { | ||||
|         int a = 5;                                int a = 5; | ||||
|         sqr(&a);                                  sqr(a); | ||||
|         cout << a << endl;                        cout << a << endl; | ||||
|     }                                         } | ||||
| 
 | ||||
|      | ||||
|     Обратите внимание на 2 вещи: | ||||
|     1)  Ссылку не нужно разыменовывать внутри функции, это происходит автоматически | ||||
| 
 | ||||
|     2)  При передаче в функцию, не нужно передавать адрес переменной | ||||
|         Нужно передать саму переменную, компилятор сам вычислит её адрес | ||||
| 
 | ||||
|         При этом копирования объекта a в функцию не происходит,  | ||||
|         ссылки работают также быстро как и указатели | ||||
| */ | ||||
| 
 | ||||
| void sqr(int& r) | ||||
| { | ||||
|     r = r * r; | ||||
| } | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a = 5; | ||||
|     sqr(a); | ||||
| 
 | ||||
|     cout << a << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
|      | ||||
|     1)  Напишите функцию void inc(int& x), которая должна принимать объект типа int | ||||
|         и увеличивать его на 1 | ||||
|         Вызовите эту функцию из main и протестируйте её работу | ||||
| 
 | ||||
|     2)  Напишите функцию void normalize(float& x, float& y), которая должна принимать  | ||||
|         2 объекта типа float и нормализировать их. То есть делить их на некоторое число, | ||||
|         так чтобы было x*x + y*y == 1 | ||||
|          | ||||
|         Для этого x и y нужно разделить на sqrt(x*x + y*y) | ||||
| 
 | ||||
| 
 | ||||
|     3)  Можно ли передать в функцию sqr не переменную, а число? | ||||
|         То есть, можно ли написать так:  | ||||
|             sqr(5) | ||||
|   | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,50 @@ | |||
| #include <iostream> | ||||
| #include <cmath> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| void inc(int& x) | ||||
| { | ||||
|     x += 1; | ||||
| } | ||||
| 
 | ||||
| void normalize(float& x, float& y) | ||||
| { | ||||
|     float norm = std::sqrt(x * x + y * y); | ||||
|     x /= norm; | ||||
|     y /= norm; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a = 5; | ||||
|     inc(a); | ||||
|     cout << a << endl; | ||||
| 
 | ||||
|     float x = 9, y = 6; | ||||
|     normalize(x, y); | ||||
|     cout << x << " " << y << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
|      | ||||
|     1)  Напишите функцию void inc(int& x), которая должна принимать объект типа int | ||||
|         и увеличивать его на 1 | ||||
|         Вызовите эту функцию из main и протестируйте её работу | ||||
| 
 | ||||
|     2)  Напишите функцию void normalize(float& x, float& y), которая должна принимать  | ||||
|         2 объекта типа float и нормализировать их. То есть делить их на некоторое число, | ||||
|         так чтобы было x*x + y*y == 1 | ||||
|          | ||||
|         Для этого x и y нужно разделить на sqrt(x*x + y*y) | ||||
| 
 | ||||
| 
 | ||||
|     3)  Можно ли передать в функцию sqr не переменную, а число? | ||||
|         То есть, можно ли написать так:  | ||||
|             sqr(5) | ||||
|   | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,81 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Чаще всего по ссылке в функцию передаются объекты структур и классов | ||||
| 
 | ||||
|     Даже если мы не хотим менять объект внутри функции, мы всё-равно можем | ||||
|     захотеть передать его по ссылке, так как передача по ссылке не копирует объект, | ||||
|     следовательно это гораздо более эффективно | ||||
| 
 | ||||
|     В этом случае передаём по константной ссылке (по аналогии с константным указателем) | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| struct Book | ||||
| { | ||||
|     char title[100]; | ||||
|     int pages; | ||||
|     float price; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| void increasePrice(Book& b, float value) | ||||
| { | ||||
|     b.price += value; | ||||
| } | ||||
| 
 | ||||
| void printBook(Book& b) | ||||
| { | ||||
|     cout << b.title << ", pages = " << b.pages << ", price = " << b.price << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Book b = {"War and Peace", 1200, 900}; | ||||
| 
 | ||||
|     printBook(b); | ||||
|     increasePrice(b, 100); | ||||
|     printBook(b); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
| // Тот же самый код с использованием указателей выглядел бы так:
 | ||||
| 
 | ||||
| void increasePrice(Book* b, float value) | ||||
| { | ||||
|     b->price += value; | ||||
| } | ||||
| 
 | ||||
| void printBook(const Book* b) | ||||
| { | ||||
|     cout << b->title << ", pages = " << b->pages << ", price = " << b->price << endl; | ||||
| } | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Book b = {"War and Peace", 1200, 900}; | ||||
| 
 | ||||
|     printBook(&b); | ||||
|     increasePrice(b, 100); | ||||
|     printBook(&b); | ||||
| } | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|     1)  Напишите функцию addPage, которая бы принимала структуру Book по ссылке | ||||
|         и увеличивала количество страниц на 1 | ||||
|         Протестируйте эту функцию в main | ||||
| 
 | ||||
|     2)  Напишите функцию changeFirstLetter, которая бы принимала структуру Book по ссылке | ||||
|         и изменяла первую букву в названии на букву A | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,41 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| struct Book | ||||
| { | ||||
|     char title[100]; | ||||
|     int pages; | ||||
|     float price; | ||||
| }; | ||||
| 
 | ||||
| void addPage(Book& b) | ||||
| { | ||||
|     b.pages++; | ||||
| } | ||||
| 
 | ||||
| void changeFirstLetter(Book& b) | ||||
| { | ||||
|     b.title[0] = 'A'; | ||||
| } | ||||
| 
 | ||||
| void printBook(const Book& b) | ||||
| { | ||||
|     cout << b.title << ", pages = " << b.pages << ", price = " << b.price << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Book b = {"War and Peace", 1200, 900}; | ||||
| 
 | ||||
|     printBook(b); | ||||
| 
 | ||||
|     addPage(b); | ||||
|     printBook(b); | ||||
| 
 | ||||
|     changeFirstLetter(b); | ||||
|     printBook(b); | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,73 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| /* 
 | ||||
|     Ссылки, как и указатели используются для передачи объектов в функции | ||||
|      | ||||
|     Рассмотрим три функции | ||||
| 
 | ||||
|         incByValue - принимаем объект по значению | ||||
|         В этом случае объект копируется и функция работает с копией | ||||
| 
 | ||||
|         incByPointer - принимаем объект по адресу | ||||
|         В этом случае внутри функции создаётся указатель, и в этот указатель | ||||
|         мы передаём адрес нашего объекта | ||||
| 
 | ||||
|         incByReference - принимаем объект по ссылке | ||||
|         В этом случае происходит всё примерно то же самое, что и в случае incByPointer | ||||
|         Только с гораздо более приятным синтаксисом | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| void incByValue(int a)  | ||||
| { | ||||
|     a += 1; | ||||
| } | ||||
| 
 | ||||
| void incByPointer(int* p)  | ||||
| { | ||||
|     *p += 1; | ||||
| } | ||||
| 
 | ||||
| void incByReference(int& a)  | ||||
| { | ||||
|     a += 1; | ||||
| } | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a = 10; | ||||
| 
 | ||||
|     cout << "1) Initial a = " << a << endl | ||||
|      | ||||
|     incByValue(a); | ||||
|     cout << "2) After incByValue a = " << a << endl; | ||||
| 
 | ||||
|     incByPointer(&a); | ||||
|     cout << "3) After incByPointer a = " << a << endl | ||||
| 
 | ||||
|     incByReference(a); | ||||
|     cout << "4) After incByReference a = " << a << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* 
 | ||||
|     Задание: | ||||
| 
 | ||||
|     1)  Напишите функции: | ||||
| 
 | ||||
|         cubeByPointer(int* p)   - принимет число по указателю и возводит это число в куб | ||||
|         cubeByReference(int& a) - принимет число по ссылке и возводит это число в куб | ||||
| 
 | ||||
|         Протестируйте эти функции в main | ||||
| 
 | ||||
| 
 | ||||
|     2)  Написать функции:  | ||||
| 
 | ||||
|         swapByPointer(int* pa, int* pb) - принимает 2 числа по указателю и обменивает их значения | ||||
|         swap(int& pa, int& pb) - принимает 2 числа по ссылке и обменивает их значения | ||||
| 
 | ||||
|         Протестируйте эти функции в main | ||||
|      | ||||
| */ | ||||
|  | @ -0,0 +1,54 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| void cubeByPointer(int* p) | ||||
| { | ||||
|     *p = *p * *p * *p; | ||||
| } | ||||
| 
 | ||||
| void cubeByReference(int& a) | ||||
| { | ||||
|     a = a * a * a; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void swapByPointer(int* pa, int* pb) | ||||
| { | ||||
|     int temp = *pa; | ||||
|     *pa = *pb; | ||||
|     *pb = temp; | ||||
| } | ||||
| 
 | ||||
| void swapByReference(int& a, int& b) | ||||
| { | ||||
|     int temp = a; | ||||
|     a = b; | ||||
|     b = temp; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a = 5; | ||||
|     cubeByPointer(&a); | ||||
|     cout << a << endl; | ||||
| 
 | ||||
|     a = 5; | ||||
|     cubeByReference(a); | ||||
|     cout << a << endl; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     int x = 10, y = 20; | ||||
|     swapByPointer(&x, &y); | ||||
|     cout << x << " " << y << endl; | ||||
| 
 | ||||
| 
 | ||||
|     x = 10;  | ||||
|     y = 20; | ||||
|     swapByReference(x, y); | ||||
|     cout << x << " " << y << endl; | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,97 @@ | |||
| #include <iostream> | ||||
| #include <cmath> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| /* 
 | ||||
|     Константные ссылки можно создать, используя ключевое слово const | ||||
| 
 | ||||
|     int a = 10; | ||||
|     const int& r = a; | ||||
| 
 | ||||
|     Это означает, что a нельзя будет изменить по этой ссылке | ||||
|     То есть поменять a, используя ссылку r будет нельзя: | ||||
|     r += 1; // Ошибка!
 | ||||
|     a += 1; // OK
 | ||||
| 
 | ||||
|      | ||||
|     Важным неочевидным отличием константных ссылок от обычных ссылок является то, что обычные ссылки | ||||
|     можно инициализировать только объектами, которые уже храняться в памяти (например, переменными). | ||||
| 
 | ||||
|     int& r1 = a;    // OK
 | ||||
|     int& r2 = 5;    // Ошибка
 | ||||
| 
 | ||||
|     Константные ссылки можно инициализировать чем угодно (нужно только чтобы тип совпадал) | ||||
| 
 | ||||
|     const int& cr1 = a; // OK
 | ||||
|     const int& cr2 = 5; // OK
 | ||||
| 
 | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a = 10; | ||||
|     const int& r = a; | ||||
| 
 | ||||
| 
 | ||||
|     int& r1 = 20;       // Это не будет компилироваться
 | ||||
|     const int& r2 = 20  // Тут всё ОК
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* 
 | ||||
|     Задание: | ||||
| 
 | ||||
|     1)  Можно ли инициализировать ссылку таким образом? | ||||
|         float& r = std::sqrt(2); | ||||
| 
 | ||||
|         Можно ли инициализировать константную ссылку таким образом? | ||||
|         const float& r = std::sqrt(2); | ||||
| 
 | ||||
| 
 | ||||
|     2)  Пусть есть функция: | ||||
| 
 | ||||
|         void printAgeV(int x) | ||||
|         { | ||||
|             cout << "My age is " << x << " years" << endl; | ||||
|         } | ||||
|      | ||||
|         Можно ли вызвать её так? | ||||
|         int a = 10; | ||||
|         printAgeV(a) | ||||
|          | ||||
|         Можно ли вызвать её так? | ||||
|         printAgeV(20) | ||||
| 
 | ||||
| 
 | ||||
|     3)  Пусть есть функция: | ||||
| 
 | ||||
|         void printAgeR(int& x) | ||||
|         { | ||||
|             cout << "My age is " << x << " years" << endl; | ||||
|         } | ||||
|      | ||||
|         Можно ли вызвать её так? | ||||
|         int a = 10; | ||||
|         printAgeR(a) | ||||
|          | ||||
|         Можно ли вызвать её так? | ||||
|         printAgeR(20) | ||||
| 
 | ||||
| 
 | ||||
|     4)  Пусть есть функция: | ||||
| 
 | ||||
|         void printAgeCR(const int& x) | ||||
|         { | ||||
|             cout << "My age is " << x << " years" << endl; | ||||
|         } | ||||
|      | ||||
|         Можно ли вызвать её так? | ||||
|         int a = 10; | ||||
|         printAgeCR(a) | ||||
|          | ||||
|         Можно ли вызвать её так? | ||||
|         printAgeCR(20) | ||||
| */ | ||||
|  | @ -0,0 +1,63 @@ | |||
| #include <iostream> | ||||
| #include <cmath> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| /* 
 | ||||
|     Константные ссылки нужны прежде всего, чтобы передавать большие объекты в функции, внутри которых они не должны меняться | ||||
| 
 | ||||
|     Рассмотрим структуру Book, чей размер более 100 байт | ||||
| 
 | ||||
|      | ||||
|     1) При передаче такой структуры в функцию по значению, как это происходит в функции printBookV, | ||||
|     вся структура будет копироваться внутрь функции и это очень медленно. Так делать не стоит. | ||||
| 
 | ||||
|      | ||||
|     2) При передаче такой структуры в функцию по обычной ссылке, как это происходит в функции printBookR, структура не копируется | ||||
|     На самом деле, под капотом внутрь функции копируется адрес структуры. | ||||
|     Адрес намного меньше самой структуры, поэтому это копирование работает намного быстрее. | ||||
| 
 | ||||
|     Но возникает проблема с тем, что структура внутри такой функции может поменяться. | ||||
|     В реальной ситуации, если функций много и они большие, уследить за тем меняется ли аргументы внутри функций становится проблематично. | ||||
| 
 | ||||
| 
 | ||||
|     3) При передаче такой структуры в функцию по константной ссылке, как это происходит в функции printBookCR, структура не копируется. | ||||
|     Плюс к этому мы можем быть уверены, что внутри функции наша структура не поменяется и это сильно упрощает понимание программы. | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| struct Book | ||||
| { | ||||
|     char title[100]; | ||||
|     int pages; | ||||
|     float price; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| void printBookV(Book b) | ||||
| { | ||||
|     cout << b.title << ", pages = " << b.pages << ", price = " << b.price << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void printBookR(Book& b) | ||||
| { | ||||
|     cout << b.title << ", pages = " << b.pages << ", price = " << b.price << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void printBookCR(const Book& b) | ||||
| { | ||||
|     cout << b.title << ", pages = " << b.pages << ", price = " << b.price << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Book b = {"War and Peace", 1200, 900}; | ||||
| 
 | ||||
|     printBookV(b); | ||||
|     printBookR(b); | ||||
|     printBookCR(b); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,50 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Ссылки можно и возвращать из функции | ||||
|     Например, функция get возвращает ссылку на глобальную переменную x | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| int x = 10; | ||||
| 
 | ||||
| 
 | ||||
| int& get()  | ||||
| { | ||||
|     return x; | ||||
| } | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     cout << x << endl; | ||||
|     cout << get() << endl; | ||||
| 
 | ||||
|     get() += 1; | ||||
|     cout << x << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     С указателями аналогичный код выглядел бы так: | ||||
| 
 | ||||
| 
 | ||||
| int x = 10; | ||||
| 
 | ||||
| int* get()  | ||||
| { | ||||
|     return &x; | ||||
| } | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     cout << x << endl; | ||||
|     cout << *get() << endl; | ||||
| 
 | ||||
|     *get() += 1; | ||||
|     cout << x << endl; | ||||
| } | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,51 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Ссылки можно и возвращать из функции | ||||
|      | ||||
|     Но при этом нужно следить за тем, чтобы функция не вернула ссылку на локальную переменную, как это происходит в данном примере. | ||||
|     После завершения функции, переменная x удалится, так как она была определена внутри функции. | ||||
| 
 | ||||
|     В результате, внутри функции main мы попробуем доступиться к области памяти, в которой раньше лежала переменная x. | ||||
|     Это приведёт к ошибке | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| int& get()  | ||||
| { | ||||
|     int x = 10; | ||||
|     return x; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     cout << get() << endl; | ||||
| 
 | ||||
|     get() += 1; | ||||
|     cout << get() << endl; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Аналогичная ошибка может произойти и при работе с обычными указателями: | ||||
| 
 | ||||
|     int* get()  | ||||
|     { | ||||
|         int x = 10; | ||||
|         return &x; | ||||
|     } | ||||
| 
 | ||||
|     int main()  | ||||
|     { | ||||
|         cout << *get() << endl; | ||||
| 
 | ||||
|         *get() += 1; | ||||
|         cout << *get() << endl; | ||||
|     } | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,39 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Ссылки можно и возвращать из функции | ||||
|     Например, функция increase принимает ссылку, увеличивет то, на что указывает эта ссылка на 1 | ||||
|     и возвращает эту ссылку | ||||
| 
 | ||||
|     При этом никакого копирование самой переменной a в функцию и из функции не происходит | ||||
| */ | ||||
| 
 | ||||
| int& increase(int& r)  | ||||
| { | ||||
|     r += 1; | ||||
|     return r; | ||||
| } | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a = 10; | ||||
| 
 | ||||
|     cout << "1) a = " << a << endl; | ||||
| 
 | ||||
|     increase(a); | ||||
|     cout << "2) a = " << a << endl; | ||||
| 
 | ||||
|     increase(a) += 7; | ||||
|     cout << "3) a = " << a << endl; | ||||
| 
 | ||||
|     increase(increase(increase(a))); | ||||
|     cout << "4) a = " << a << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Что напечатает данная программа? | ||||
| */ | ||||
|  | @ -0,0 +1,17 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задача: | ||||
| 
 | ||||
|         Напишите функцию multiplyBy2, которая принимает число по ссылке и увеличивает его в 2 раза | ||||
|         Вызовите эту функцию из функции main | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,16 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| void multiplyBy2(int& a) | ||||
| { | ||||
|     a *= 2; | ||||
| } | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int x = 10; | ||||
|     multiplyBy2(x); | ||||
|     cout << x << endl; | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,22 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задача: | ||||
| 
 | ||||
|         Напишите функцию sumAndSave, которая должна принимать 3 аргумента | ||||
|         Первые два аргумента по значению | ||||
|         Третий аргумент по ссылке | ||||
| 
 | ||||
|         Функция должна складывать первые 2 аргумента и сохранять результат по третей ссылке | ||||
| 
 | ||||
|         Вызовите эту функцию из функции main | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,36 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задача: | ||||
| 
 | ||||
|         Напишите функцию sumAndSave, которая должна принимать 3 аргумента | ||||
|         Первые два аргумента по значению | ||||
|         Третий аргумент по ссылке | ||||
| 
 | ||||
|         Функция должна складывать первые 2 аргумента и сохранять результат по третей ссылке | ||||
| 
 | ||||
|         Вызовите эту функцию из функции main | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| void sumAndSave(int a, int b, int& c) | ||||
| { | ||||
|     c = a + b; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int x = 10, y = 20; | ||||
|     int z; | ||||
| 
 | ||||
|     sumAndSave(x, y, z); | ||||
|     cout << z << endl; | ||||
| 
 | ||||
| 
 | ||||
|     sumAndSave(70, 80, z); | ||||
|     cout << z << endl; | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,28 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задача: | ||||
| 
 | ||||
|         Напишите функцию  | ||||
| 
 | ||||
|             void calculateLetters(char str[], int& numLetters) | ||||
| 
 | ||||
|         Которая будет принимать на вход строку и считать количество строчных букв в этой строке | ||||
|         Строчные буквы - это символы от 'a' и до 'z' | ||||
| 
 | ||||
|         Например, вызов calculateLetters("ab54AB,gd1:e", x) должен сохранить число 5 в переменную x | ||||
| 
 | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
| 
 | ||||
|     int x; | ||||
|     calculateLetters("ab54AB,gd1:e", x); | ||||
|     cout << x << endl; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,23 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void calculateLetters(char str[], int& numLetters) | ||||
| { | ||||
|     numLetters = 0; | ||||
|     for (int i = 0; str[i] != '\0'; ++i) | ||||
|     { | ||||
|         if (str[i] >= 'a' && str[i] <= 'z') | ||||
|             numLetters += 1; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int x; | ||||
|     calculateLetters("ab54AB,gd1:e", x); | ||||
|     cout << x << endl; | ||||
| } | ||||
| 
 | ||||
		Reference in a new issue