initial commit
This commit is contained in:
		
						commit
						2369f801af
					
				
					 76 changed files with 4273 additions and 0 deletions
				
			
		|  | @ -0,0 +1,33 @@ | |||
| #include <stdio.h> | ||||
| 
 | ||||
| /*
 | ||||
|     Здравствуйте, это первый файл семестра по языку C++  (для тех, кто знаком с языком C) | ||||
| 
 | ||||
|     Язык C++ создан на основе языка C и одним из приоритетов C++ является обратная совместимость с C | ||||
|     Поэтому почти любая программа на языке C будет работать и на языке C++ | ||||
| 
 | ||||
|     Однако, нужно помнить, что это разные языки. В C++ было добавлено огромное количество новых возможностей,  | ||||
|     что сделало C++ возможно самым объёмным и мощным языком программирования. | ||||
| 
 | ||||
|     C++ содержит в себе во много раз больше всего, чем язык C и пройти его за один семестр не представляется возможным, | ||||
|     но мы пройдём ключевые части этого языка. | ||||
| 
 | ||||
| 
 | ||||
|     Для компиляции программ на C++ будем использовать компилятор g++. | ||||
|     Скомпилируйте эту программу вот так: | ||||
|         g++ 00hello.cpp | ||||
|      | ||||
|     И запустите вот так (для Windows): | ||||
|         a.exe | ||||
| 
 | ||||
|     И запустите вот так (для Linux): | ||||
|         ./a.out | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     printf("Hello World of C++\n"); | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,48 @@ | |||
| #include <stdio.h> | ||||
| 
 | ||||
| /*
 | ||||
|     Пространства имён - namespace | ||||
| 
 | ||||
|     Определяем переменные/структуры/функции внутри пространства имён. | ||||
|     Давайте назовём его mipt | ||||
| 
 | ||||
|     Чтобы получить доступ к этим переменным/структурам/функциям | ||||
|     вне пространства имён, нужно добавить к имени название пространства имён и оператор ::  | ||||
|     В данном случае нужно добавить mipt:: | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| namespace mipt  | ||||
| { | ||||
|     int a = 5; | ||||
|     float b = 1.2; | ||||
| 
 | ||||
|     int square(int x) | ||||
|     { | ||||
|         return x * x; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     printf("%i\n", mipt::square(4)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задание: | ||||
| 
 | ||||
|     1)  Скомпилируйте программу и запустите, что она напечатает? | ||||
| 
 | ||||
|     2)  Что будет, если забыть написать mipt:: у названия функции square? | ||||
| 
 | ||||
|     3)  Передайте в функцию mipt::square переменную a из пространства имён mipt | ||||
| 
 | ||||
|     4)  Напишите функцию float average(float x, float y), которая будет принимать 2 числа | ||||
|         и возвращать их среднее арифметическое. | ||||
|         Поместите эту функцию в пространство имён mipt и вызовите эту функцию из main | ||||
| 
 | ||||
|     5)  Напечатайте среднее арифметическое от a и b, используя функцию average | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,25 @@ | |||
| #include <stdio.h> | ||||
| 
 | ||||
| 
 | ||||
| namespace mipt  | ||||
| { | ||||
|     int a = 5; | ||||
|     float b = 1.2; | ||||
| 
 | ||||
|     int square(int x) | ||||
|     { | ||||
|         return x * x; | ||||
|     } | ||||
| 
 | ||||
|     float average(float x, float y) | ||||
|     { | ||||
|         return (x + y) / 2; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     printf("%i\n", mipt::square(mipt::a)); | ||||
|     printf("%f\n", mipt::average(mipt::a, mipt::b)); | ||||
| } | ||||
|  | @ -0,0 +1,24 @@ | |||
| #include <stdio.h> | ||||
| 
 | ||||
| /*
 | ||||
|     В языке C   при объявлении структуры struct Book создаётся тип по имени struct Book.  | ||||
| 
 | ||||
|     В языке C++ при объявлении структуры struct Book создаётся тип к которому | ||||
|     можно обращаться как по имени struct Book так и по имени Book | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| struct Book  | ||||
| { | ||||
|     char title[50]; | ||||
|     int pages; | ||||
|     float price; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     struct Book a = {"Tom Sawyer", 280, 500}; | ||||
| 
 | ||||
|     Book b = {"War and Peace", 1200, 900}; | ||||
| } | ||||
|  | @ -0,0 +1,40 @@ | |||
| #include <cstdio> | ||||
| 
 | ||||
| /*
 | ||||
|     Определяем переменные/структуры/функции внутри пространства имён mipt | ||||
|     Затем к ним можно будет доступиться используя префикс mipt:: | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| namespace mipt  | ||||
| { | ||||
|     struct Book  | ||||
|     { | ||||
|         char title[50]; | ||||
|         int pages; | ||||
|         float price; | ||||
|     }; | ||||
| 
 | ||||
|     void printBook(Book b) | ||||
|     { | ||||
|         printf("%s, pages: %d, price: %.2f\n", b.title, b.pages, b.price); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     Задание: | ||||
| 
 | ||||
|     Структура Book и функция printBook определены в пространстве имён mipt | ||||
| 
 | ||||
|     1)  Создайте переменную типа структура Book и иницилизируйте | ||||
|         её значениями: "War and Peace", 1200, 900 | ||||
| 
 | ||||
|     2)  Напечатайте созданную переменную с помощью функции printBook | ||||
| */ | ||||
|  | @ -0,0 +1,36 @@ | |||
| #include <cstdio> | ||||
| 
 | ||||
| 
 | ||||
| namespace mipt  | ||||
| { | ||||
|     struct Book  | ||||
|     { | ||||
|         char title[50]; | ||||
|         int pages; | ||||
|         float price; | ||||
|     }; | ||||
| 
 | ||||
|     void printBook(Book b) | ||||
|     { | ||||
|         printf("%s, pages: %d, price: %.2f\n", b.title, b.pages, b.price); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     mipt::Book b = {"War and Peace", 1200, 900}; | ||||
|     mipt::printBook(b); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     Задание: | ||||
| 
 | ||||
|     Структура Book и функция printBook определены в пространстве имён mipt | ||||
| 
 | ||||
|     1)  Создайте переменную типа структура Book и иницилизируйте | ||||
|         её значениями: "War and Peace", 1200, 900 | ||||
| 
 | ||||
|     2)  Напечатайте созданную переменную с помощью функции printBook | ||||
| */ | ||||
|  | @ -0,0 +1,60 @@ | |||
| #include <stdio.h> | ||||
| 
 | ||||
| /*
 | ||||
|     Зачем вообще нужны пространства имён? | ||||
| 
 | ||||
|     Представьте, что вы создаёте большую программу, исходный код который | ||||
|     содержит миллионы строк кода. Конечно, большая часть кода написана не вами,  | ||||
|     так как вы используете библиотеки, написанные другими программистами. | ||||
| 
 | ||||
|     Библиотекой можно назвать совокупность файлов исходного кода, нацеленных | ||||
|     на решение какой-либо задачи. Например, есть библиотека для работы с графикой | ||||
|     в которой содержатся функции/структуры/классы для работы с графикой. | ||||
| 
 | ||||
|     Если вы подключаете несколько библиотек, то существует высокая вероятность,  | ||||
|     что название чего-либо из одной библиотеки совпадёт с названием чего-то из другой библиотеки. | ||||
|     Это, конечно, приведёт к ошибке. | ||||
| 
 | ||||
|     Чтобы этого избежать и используются пространства имён. | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| namespace audio  | ||||
| { | ||||
|     int a = 10; | ||||
| 
 | ||||
|     int calculate(int x) | ||||
|     { | ||||
|         return x + 1; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| namespace graphics  | ||||
| { | ||||
|     int a = 20; | ||||
| 
 | ||||
|     int calculate(int x) | ||||
|     { | ||||
|         return x * 2; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     printf("%i\n", audio::a); | ||||
|     printf("%i\n", graphics::a); | ||||
| 
 | ||||
| 
 | ||||
|     printf("%i\n", graphics::calculate(audio::calculate(graphics::a))); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задание: | ||||
| 
 | ||||
|     1)  Что напечатает данная программа? | ||||
| */ | ||||
|  | @ -0,0 +1,78 @@ | |||
| #include <stdio.h> | ||||
| 
 | ||||
| /*
 | ||||
|     Если вам очень не хочется постоянно писать названия пространства имён, | ||||
|     то вы можете использовать ключевое слово using | ||||
| 
 | ||||
|         using namespace audio; | ||||
| 
 | ||||
|     Это говорит о том, что начиная с этой строки audio:: перед именами писать больше не нужно | ||||
| 
 | ||||
|     Это, конечно, полностью уничтожают всю пользу, которую приносят пространства имён. | ||||
|     То есть в больших проектах могут возникнуть ошибки, связанные с одинаковыми именами. | ||||
| 
 | ||||
|     Так что так лучше не делать, а если и делать, то только в маленьких программах. | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| namespace audio  | ||||
| { | ||||
|     int a = 10; | ||||
| 
 | ||||
|     int calculate(int x) | ||||
|     { | ||||
|         return x + 1; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| namespace graphics  | ||||
| { | ||||
|     int a = 20; | ||||
| 
 | ||||
|     int calculate(int x) | ||||
|     { | ||||
|         return x * 2; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| namespace network  | ||||
| { | ||||
|     int b = 20; | ||||
| 
 | ||||
|     int solve(int x) | ||||
|     { | ||||
|         return x * 2; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| using namespace audio; | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     printf("%i\n", calculate(a)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задание: | ||||
| 
 | ||||
|     1)  Что напечатает данная программа? | ||||
| 
 | ||||
|     2)  Если заменить  using namespace audio  на  using namespace graphics, то что напечатает программа? | ||||
| 
 | ||||
|     3)  Что если одновременно использовать пространство имён audio и пространство имён graphics? | ||||
| 
 | ||||
|             using namespace audio; | ||||
|             using namespace graphics; | ||||
| 
 | ||||
|         Приведёт ли это к ошибке и, если да, то почему? | ||||
| 
 | ||||
| 
 | ||||
|     4)  Что если одновременно использовать пространство имён audio и пространство имён network? | ||||
| 
 | ||||
|             using namespace audio; | ||||
|             using namespace network; | ||||
| 
 | ||||
|         Приведёт ли это к ошибке и, если да, то почему? | ||||
| */ | ||||
|  | @ -0,0 +1,65 @@ | |||
| #include <iostream> | ||||
| 
 | ||||
| /*
 | ||||
|     Все переменные/функции/структуры/классы стандартной библиотеки языка C++ содержатся в пространстве имён std | ||||
|     Рассмотрим, например, глобальную переменную cout, определённую в библиотеке iostream в пространстве имён std. | ||||
| 
 | ||||
|     К этой переменной можно применять оператор << | ||||
|         cout << объект | ||||
|     В результате этой операции объект напечатается на экран (если он может напечататься) | ||||
|     Результат оператора << также является cout, поэтому можно применять << несколько раз: | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     Например это выражение:   cout << "Hello " << "World" << "\n"; | ||||
| 
 | ||||
|         1)  Сначала напечатается "Hello " и на место  cout << "Hello "  подставится  cout | ||||
|             Получтся cout << "World" << "\n"; | ||||
| 
 | ||||
|         2)  Потом напечатется "World" и на место  cout << "World"  подставится  cout | ||||
|             Получтся cout << "\n"; | ||||
| 
 | ||||
|         3)  В конце напечатается перенос строки | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     std::cout << "Hello World\n"; | ||||
|     std::cout << 5 << "\n"; | ||||
| 
 | ||||
|     int x = 10; | ||||
|     std::cout << 5 << "\n"; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|         1)  Напечатайте на экран число 1.4, используя cout  (количество печатаемых знаков после запятой неважно) | ||||
|             Обратите внимание, что при печати с cout не нужно указывать спецификатор типа как в printf. | ||||
|             cout сам понимает объект какого типа ему передаётся | ||||
| 
 | ||||
|         2)  Напечатайте фразу "I am x years old", только за место x нужно подставить значение | ||||
|             переменной x. В данной задаче получится "I am 10 years old". Используйте cout. | ||||
| 
 | ||||
|         3)  Напечатайте на экран числа от 1 до 20, разделённые пробелом. Используйте cout | ||||
| 
 | ||||
|         4)  Вместо \n для переноса строки можно использовать endl - специальный объект из | ||||
|             пространства имён std. | ||||
|             Если мы передаём его объекту cout через оператор << то печатается перенос строки | ||||
|              | ||||
|             Замените все переносы строк с \n на endl | ||||
|             std::cout << 5 << "\n";  -->  std::cout << 5 << std::endl; | ||||
| 
 | ||||
| 
 | ||||
|             На самом деле std::endl работает медленней, чем \n, так как он помимо печати делает flush | ||||
|             Поэтому, если важна скорость печати в буфер, то лучше использовать \n | ||||
| 
 | ||||
| 
 | ||||
|         5)  Что будет если не написать std:: перед одним из cout? | ||||
| 
 | ||||
|         6)  Используйте using namespace std; и избавьтесь от надоедливых std:: перед cout и endl | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,16 @@ | |||
| #include <iostream> | ||||
| using namespace std; | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     cout << 1.4 << endl; | ||||
| 
 | ||||
|     int x = 10; | ||||
|     cout << "I am " << x << " years old" << endl; | ||||
| 
 | ||||
|     for (int i = 1; i <= 20; ++i) | ||||
|         cout << i << " "; | ||||
|     cout << endl; | ||||
|      | ||||
| } | ||||
|  | @ -0,0 +1,32 @@ | |||
| #include <iostream> | ||||
| 
 | ||||
| /*
 | ||||
|     В пространстве имён std очень много разных имён. Если мы добавим их всех, используя  | ||||
|         using namespace std; | ||||
|     то это может привести к проблеме. | ||||
|     Одно из имён из std может совпасть с названием нашего объекта и это может привести к ошибке. | ||||
| 
 | ||||
|     Так что лучше такую возможность не использовать. | ||||
| 
 | ||||
|     Но можно добавить только одно имя так: | ||||
|         using std::cout; | ||||
|     Начиная с этого момента можно писать просто cout. | ||||
|     Но для всех остальных объектов из std вы должны продолжать писать std:: | ||||
| */ | ||||
| 
 | ||||
| using std::cout; | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     cout << "Hello World" << std::endl; | ||||
|     cout << 5 << std::endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|         1)  Добавить endl в нашу область видимости, также как и cout | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,41 @@ | |||
| #include <iostream> | ||||
| 
 | ||||
| /*
 | ||||
|     Счтиывание из стандартного входа | ||||
|      | ||||
|     Рассмотрим глобальную переменную cin, определённую в библиотеке iostream в пространстве имён std. | ||||
| 
 | ||||
|     К этой переменной можно применять оператор >> | ||||
|         cin >> объект | ||||
|     В результате этой операции объект считается с экрана (если он может быть считан) | ||||
|     Результат оператора >> также является cin, поэтому можно применять >> несколько раз: | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     Например это выражение:   cin >> a >> b; | ||||
| 
 | ||||
|         1)  Сначала считается переменная a и на место  cin >> a  подставится  cin | ||||
|             Получтся cin >> b; | ||||
| 
 | ||||
|         2)  Потом считается переменная b | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a, b; | ||||
|     std::cin >> a >> b; | ||||
|     std::cout << a + b; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|         1)  Что напечатает данная программа, если на вход передать числа 10 и 20? | ||||
| 
 | ||||
|         2)  Напишите программу, которая будет считывать два вещественных числа и печатать их среднее геометрическое | ||||
|             Функция корня sqrt есть в библиотеке <cmath> | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,10 @@ | |||
| #include <iostream> | ||||
| #include <cmath> | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     float a, b; | ||||
|     std::cin >> a >> b; | ||||
|     std::cout << sqrt(a * b); | ||||
| } | ||||
|  | @ -0,0 +1,42 @@ | |||
| #include <stdio.h> | ||||
| #include <math.h> | ||||
| 
 | ||||
| /*
 | ||||
|     Язык C++ обратно совместим с языком C. То есть почти любая программа на C будет работать на C++ | ||||
|     Эта программа будет работать. | ||||
| 
 | ||||
|     Обратите внимания, для имён, пришедших из языка C использовать std:: не обязательно | ||||
| 
 | ||||
|     Программа работает, несмотря на то, что мы используем библиотечные  | ||||
|     функции printf и sqrt без указания пространства имён std. | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     printf("%f", sqrt(3)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*  Задача:
 | ||||
| 
 | ||||
|     1)  Что напечатает данная программа? | ||||
| 
 | ||||
|     2)  Использование библиотечных функций без std опасно, так как может привести к ошибкам, | ||||
|         связанных с совпадением имён. Помните, что большая программа может иметь миллионы | ||||
|         строк кода и совпадение ваших имен и библиотечных имён очень вероятно. | ||||
| 
 | ||||
| 
 | ||||
|         Напишите следующую функцию перед функцией main | ||||
|          | ||||
|         int sqrt(int x) | ||||
|         { | ||||
|             return x + 1; | ||||
|         } | ||||
| 
 | ||||
|         Что теперь напечатает программа? Объясните результат. | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,37 @@ | |||
| #include <cstdio> | ||||
| #include <cmath> | ||||
| 
 | ||||
| /*
 | ||||
|     Желательно всё равно использовать std даже для имён пришедших из языка C | ||||
| 
 | ||||
|     Также были изменены названия библиотек: | ||||
|         stdio.h  -->  cstdio | ||||
|         math.h   -->  cmath | ||||
|     cmath означает, что это библиотека языка C под названием math, поэтому и cmath | ||||
| 
 | ||||
|     Они почти не отличаются от предыдущих, но при программировании на C++ | ||||
|     желательно использовать именно эти библиотеки. | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     std::printf("%f", std::sqrt(3)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*  Задача:
 | ||||
| 
 | ||||
|     1)  Что напечатает данная программа? | ||||
| 
 | ||||
|     2)  Напишите следующую функцию перед функцией main | ||||
|          | ||||
|         int sqrt(int x) | ||||
|         { | ||||
|             return x + 1; | ||||
|         } | ||||
| 
 | ||||
|         Что теперь напечатает программа? Объясните результат. | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										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; | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,61 @@ | |||
| #include <stdio.h> | ||||
| 
 | ||||
| /*
 | ||||
|     Это программа на языке C и компилировать её надо так: | ||||
|         gcc 00cfunctions.c | ||||
| 
 | ||||
| 
 | ||||
|     Известно, что в языке C нельзя создать две функции с одинаковым названием | ||||
|     Но часто требуется написать функции, которые будут делать похожие вещи, но для разных типов данных. | ||||
|     Простейший пример -- математические функции для разных численных типов данных | ||||
| 
 | ||||
|     В языке C эта проблема решается так, что функциям даются немного различающиеся имена | ||||
| 
 | ||||
| 
 | ||||
|     В данном примере мы создали функции для вычисления абсолютного значения для типов int и double | ||||
|     Всё работает хорошо, пока мы соблюдаем типы данных и функции | ||||
| 
 | ||||
|     Но стоит ошибиться и произойдёт сложно выявляемая ошибка | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| int abs(int a) | ||||
| { | ||||
|     if (a < 0) | ||||
|         return -a; | ||||
|     else  | ||||
|         return a; | ||||
| } | ||||
| 
 | ||||
| double fabs(double a) | ||||
| { | ||||
|     if (a < 0) | ||||
|         return -a; | ||||
|     else  | ||||
|         return a; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
|     printf("%i\n", abs(-5)); | ||||
|     printf("%lf\n", fabs(-5.9)); | ||||
| 
 | ||||
| 
 | ||||
|     double x = abs(-5.9); | ||||
|     printf("%lf\n", x); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задача: | ||||
| 
 | ||||
|         1)  В данном примере переменная x равна ровно 5. Почему так происходит? | ||||
| 
 | ||||
|         2)  Что будет, если всё-таки назвать 2 функции одинаковым именем и скомпилировать программу с помощью gcc? | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,66 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| /*
 | ||||
|     Это программа на языке C++ и компилировать её надо так: | ||||
|         g++ 01cppfunctions.c | ||||
| 
 | ||||
| 
 | ||||
|     В отличии от языка C в языке C++ есть возможность создать 2 и больше разных функции с одним и тем же названием, | ||||
|     но с разным количеством и/или типами аргументов. | ||||
| 
 | ||||
|     Компилятор сам догадается, какую функцию следует вызвать в зависимости от типа аргумента. | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| int abs(int a) | ||||
| { | ||||
|     if (a < 0) | ||||
|         return -a; | ||||
|     else  | ||||
|         return a; | ||||
| } | ||||
| 
 | ||||
| double abs(double a) | ||||
| { | ||||
|     if (a < 0) | ||||
|         return -a; | ||||
|     else  | ||||
|         return a; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
|     cout << abs(-5)   << endl; | ||||
|     cout << abs(-5.9) << endl; | ||||
| 
 | ||||
| 
 | ||||
|     double x = abs(-5.9); | ||||
|     cout << x << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|     1)  Протестируйте, что компилятор действительно вызывает нужные функции | ||||
|         Для этого просто сделайте так, чтобы функция, которая принимает int печатала на экран слово int, | ||||
|         а функция, которая принимает double, печатала бы на экран слово double | ||||
| 
 | ||||
| 
 | ||||
|     2)  Что если на вход функции abs передать тип float? | ||||
|         Например, вот так:  | ||||
|             abs(1.5f) | ||||
| 
 | ||||
|         Какая из функций вызовется? | ||||
| 
 | ||||
| 
 | ||||
|     3)  Напишите ещё одну перегрузку функции abs для типа float | ||||
|         Протестируйте её в функции main | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,30 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| /*
 | ||||
|     Задача: | ||||
| 
 | ||||
|         Напишите несколько перегруженных функций под названием max | ||||
| 
 | ||||
|         1) max, который вычисляет максимум от двух чисел типа int | ||||
|         2) max, который вычисляет максимум от двух чисел типа double | ||||
|         3) max, который вычисляет максимум от трёх чисел типа int | ||||
|         4) max, который вычисляет максимум от трёх чисел типа double | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| int max(int a, int b) | ||||
| { | ||||
|     if (a > b) | ||||
|         return a; | ||||
|     else | ||||
|         return b; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     cout << max(4.2, 2.8) << endl;      // Выводит число 4 -- неправильно
 | ||||
| } | ||||
|  | @ -0,0 +1,53 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| int max(int a, int b) | ||||
| { | ||||
|     if (a > b) | ||||
|         return a; | ||||
|     else | ||||
|         return b; | ||||
| } | ||||
| 
 | ||||
| double max(double a, double b) | ||||
| { | ||||
|     if (a > b) | ||||
|         return a; | ||||
|     else | ||||
|         return b; | ||||
| } | ||||
| 
 | ||||
| int max(int a, int b, int c) | ||||
| { | ||||
|     int result = a; | ||||
|     if (b > result) | ||||
|         result = b; | ||||
|     if (c > result) | ||||
|         result = c; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| double max(double a, double b, double c) | ||||
| { | ||||
|     double result = a; | ||||
|     if (b > result) | ||||
|         result = b; | ||||
|     if (c > result) | ||||
|         result = c; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     cout << max(4.2, 2.8) << endl; | ||||
| 
 | ||||
|     cout << max(1, 2) << endl; | ||||
| 
 | ||||
|     cout << max(4, 2, 5) << endl; | ||||
| 
 | ||||
|     cout << max(1.2, 2.1, 0.5) << endl; | ||||
| } | ||||
|  | @ -0,0 +1,42 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| /*
 | ||||
|     Задача: | ||||
| 
 | ||||
|         Напишите несколько перегруженных функций под названием printType | ||||
| 
 | ||||
|         Эти функции должны печатать тип переменной, которая поступает на вход | ||||
|      | ||||
| 
 | ||||
|         printType(15)       должен напечатать int | ||||
|         printType(1.5)      должен напечатать double | ||||
|         printType(1.5f);    должен напечатать float | ||||
|         printType("Hello"); должен напечатать char[] | ||||
| 
 | ||||
|         book b = {"War and Peace", 900, 1200}; | ||||
|         printType(b);       должен напечатать book | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| struct book  | ||||
| { | ||||
|     char title[50]; | ||||
|     float price; | ||||
|     int pages; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     printType(15); | ||||
|     printType(1.5); | ||||
|     printType(1.5f); | ||||
|     printType("Hello"); | ||||
| 
 | ||||
|     book b = {"War and Peace", 900, 1200}; | ||||
|     printType(b); | ||||
| } | ||||
|  | @ -0,0 +1,66 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| /*
 | ||||
|     Задача: | ||||
| 
 | ||||
|         Напишите несколько перегруженных функций под названием printType | ||||
| 
 | ||||
|         Эти функции должны печатать тип переменной, которая поступает на вход | ||||
|      | ||||
| 
 | ||||
|         printType(15)       должен напечатать int | ||||
|         printType(1.5)      должен напечатать double | ||||
|         printType(1.5f);    должен напечатать float | ||||
|         printType("Hello"); должен напечатать char[] | ||||
| 
 | ||||
|         book b = {"War and Peace", 900, 1200}; | ||||
|         printType(b);       должен напечатать book | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| struct book  | ||||
| { | ||||
|     char title[50]; | ||||
|     float price; | ||||
|     int pages; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| void printType(int a) | ||||
| { | ||||
|     cout << "int" << endl; | ||||
| } | ||||
| 
 | ||||
| void printType(double a) | ||||
| { | ||||
|     cout << "double" << endl; | ||||
| } | ||||
| 
 | ||||
| void printType(float a) | ||||
| { | ||||
|     cout << "float" << endl; | ||||
| } | ||||
| 
 | ||||
| void printType(const char a[]) | ||||
| { | ||||
|     cout << "char[]" << endl; | ||||
| } | ||||
| 
 | ||||
| void printType(const book& a) | ||||
| { | ||||
|     cout << "book" << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     printType(15); | ||||
|     printType(1.5); | ||||
|     printType(1.5f); | ||||
|     printType("Hello"); | ||||
| 
 | ||||
|     book b = {"War and Peace", 900, 1200}; | ||||
|     printType(b); | ||||
| } | ||||
|  | @ -0,0 +1,17 @@ | |||
| #include <iostream> | ||||
| #include <cmath> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| /*
 | ||||
|     В отличии от языка C в языке C++ стандартные математические функции уже перегружены и могут | ||||
|     работать с разными типами данных | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     cout << std::abs(-4) << endl; | ||||
|     cout << std::abs(-4.2) << endl; | ||||
|     cout << std::abs(-4.2f) << endl; | ||||
| } | ||||
|  | @ -0,0 +1,67 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| /*
 | ||||
|     Функции можно перегружать и по указателю и ссылке | ||||
| 
 | ||||
|     Но в случае с перегрузкой по ссылке могут возникнуть ситуации при которых невозможно выбрать правильный | ||||
| 
 | ||||
|     Например, при вызове | ||||
| 
 | ||||
|         int a = 10; | ||||
|         func(a); | ||||
| 
 | ||||
|     Можно выбрать функцию void func(int x)  или  void func(int& x)  | ||||
|     Определить более правильную функцию в этом случае невозможно, это приведёт к ошибке | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| void func(int x)  | ||||
| { | ||||
|     cout << "int x" << endl; | ||||
| } | ||||
| 
 | ||||
| void func(int* x)  | ||||
| { | ||||
|     cout << "int* x" << endl; | ||||
| } | ||||
|      | ||||
| 
 | ||||
| void func(int& x)  | ||||
| { | ||||
|     cout << "int& x" << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     int a = 10; | ||||
|     int* p = &a; | ||||
|     int& r = a; | ||||
| 
 | ||||
|     func(a); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|     1)  Определите какая функция вызовется при следующих вызовах функции func или произойдёт ошибка | ||||
| 
 | ||||
|             1)  func(a) | ||||
|             2)  func(p) | ||||
|             3)  func(&a) | ||||
|             4)  func(20) | ||||
|             5)  func(r) | ||||
|             6)  func(&r) | ||||
| 
 | ||||
|      | ||||
|     2)  Если добавить перегрузку, принимающую по константной ссылке, то что изменится | ||||
|      | ||||
|             void func(const int& x)  | ||||
|             { | ||||
|                 cout << "const int& x" << endl; | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,30 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| struct Cat {}; | ||||
| struct Dog {}; | ||||
| struct Cow {}; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void say(Cat a) | ||||
| { | ||||
|     cout << "Meow" << endl; | ||||
| } | ||||
| 
 | ||||
| void say(Dog a) | ||||
| { | ||||
|     cout << "Woof" << endl; | ||||
| } | ||||
| 
 | ||||
| void say(Cow a) | ||||
| { | ||||
|     cout << "Mooo" << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
|     Cow x; | ||||
|     say(x); | ||||
| } | ||||
|  | @ -0,0 +1,48 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Предположим, что мы захотели создать структуру, который будет хранить время (для простоты, только минуты и секунды) | ||||
| 
 | ||||
|     Нам может понадобиться функция, которая будет добавлять ко времени, некоторое количество секунд | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| struct Time  | ||||
| { | ||||
|     int minutes; | ||||
|     int seconds; | ||||
| }; | ||||
| 
 | ||||
| Time add(Time t, int x) | ||||
| { | ||||
|     Time result = t; | ||||
|     result.seconds += x; | ||||
|      | ||||
|     result.minutes += (result.seconds / 60); | ||||
|     result.seconds %= 60; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Time a = {20, 10}; | ||||
|     Time b = add(a, 90); | ||||
| 
 | ||||
|     cout << b.minutes << " " << b.seconds << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
| 
 | ||||
|     Задача: | ||||
|          | ||||
|         1)  Напишите функцию, которая будет складывать не время и число, а два времени | ||||
| 
 | ||||
|             Time add(Time ta, Time tb) | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,44 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| struct Time  | ||||
| { | ||||
|     int minutes; | ||||
|     int seconds; | ||||
| }; | ||||
| 
 | ||||
| Time add(Time t, int x) | ||||
| { | ||||
|     Time result = t; | ||||
|     result.seconds += x; | ||||
|      | ||||
|     result.minutes += (result.seconds / 60); | ||||
|     result.seconds %= 60; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| Time add(Time ta, Time tb) | ||||
| { | ||||
|     Time result = ta; | ||||
|     result.seconds += 60 * tb.minutes + tb.seconds; | ||||
|      | ||||
|     result.minutes += (result.seconds / 60); | ||||
|     result.seconds %= 60; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Time a = {20, 10}; | ||||
|     Time b = add(a, 90); | ||||
|     Time c = add(a, b); | ||||
| 
 | ||||
|     cout << b.minutes << " " << b.seconds << endl; | ||||
|     cout << c.minutes << " " << c.seconds << endl; | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,63 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Использовать функции может быть не так удобно как операторы. | ||||
|     Возможно было бы удобней для добавления времени использовать не функцию add, а оператор + | ||||
| 
 | ||||
|     Можно перегрузить оператор функцией, для этого нужно назвать функцию так: operator@ | ||||
|     где за место @ нужно подставить оператор, который вы хотите перегрузить | ||||
| 
 | ||||
|     Например, функция Time operator+(Time t, int x) перегружает оператор + для типов Time и int соответственно (обязательно в таком порядке) | ||||
|     Теперь, когда компилятор встретит в коде сложение с таким операндами он вызовет эту функцию | ||||
| 
 | ||||
|     В этом примере  a + 90  при компиляции преобразуется в вызов функции  operator+(a, 90) | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| struct Time  | ||||
| { | ||||
|     int minutes; | ||||
|     int seconds; | ||||
| }; | ||||
| 
 | ||||
| Time operator+(Time t, int x) | ||||
| { | ||||
|     Time result = t; | ||||
|     result.seconds += x; | ||||
|      | ||||
|     result.minutes += (result.seconds / 60); | ||||
|     result.seconds %= 60; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Time a = {20, 10}; | ||||
|     Time b = a + 90; | ||||
| 
 | ||||
|     cout << b.minutes << " " << b.seconds << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
| 
 | ||||
|     Задача: | ||||
| 
 | ||||
|         1)  Что если операторы сложения поменяются местами | ||||
|                 Time b = 90 + a; | ||||
|             Сработает ли в этом случае наша функция operator+ и, если нет, что нужно добавить, чтобы такое сложение сработало? | ||||
|          | ||||
| 
 | ||||
|         2)  Напишите перегруженный оператор, который будет складывать не время и число, а два времени | ||||
| 
 | ||||
|                 Time operator+(Time ta, Time tb) | ||||
| 
 | ||||
| 
 | ||||
|          | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,50 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| struct Time  | ||||
| { | ||||
|     int minutes; | ||||
|     int seconds; | ||||
| }; | ||||
| 
 | ||||
| Time operator+(Time t, int x) | ||||
| { | ||||
|     Time result = t; | ||||
|     result.seconds += x; | ||||
|      | ||||
|     result.minutes += (result.seconds / 60); | ||||
|     result.seconds %= 60; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| Time operator+(int x, Time t) | ||||
| { | ||||
|     return t + x; | ||||
| } | ||||
| 
 | ||||
| Time operator+(Time ta, Time tb) | ||||
| { | ||||
|     Time result = ta; | ||||
|     result.seconds += 60 * tb.minutes + tb.seconds; | ||||
|      | ||||
|     result.minutes += (result.seconds / 60); | ||||
|     result.seconds %= 60; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Time a = {20, 10}; | ||||
|     Time b = a + 90; | ||||
|     Time c = 90 + a; | ||||
|     Time d = a + b; | ||||
| 
 | ||||
|     cout << b.minutes << " " << b.seconds << endl; | ||||
|     cout << c.minutes << " " << c.seconds << endl; | ||||
|     cout << d.minutes << " " << d.seconds << endl; | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,71 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Помимо перегрузки операторов, принимающих 2 аргумента (бинарных) | ||||
|     можно перегружать и унарные операторы - принимающие один аргумент | ||||
| 
 | ||||
|     При этом, так как operator+ это функция, то работает перегрузка функций | ||||
| 
 | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| struct Time  | ||||
| { | ||||
|     int minutes; | ||||
|     int seconds; | ||||
| }; | ||||
| 
 | ||||
| Time operator+(Time ta, Time tb) | ||||
| { | ||||
|     cout << "binary operator +" << endl; | ||||
| 
 | ||||
|     Time result = ta; | ||||
|     result.seconds += 60 * tb.minutes + tb.seconds; | ||||
|      | ||||
|     result.minutes += (result.seconds / 60); | ||||
|     result.seconds %= 60; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| Time operator+(Time t) | ||||
| { | ||||
|     cout << "unary operator +" << endl; | ||||
| 
 | ||||
|     return t; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Time a = {20, 10}; | ||||
|     Time b = {40, 30}; | ||||
| 
 | ||||
|     Time c = a + b; | ||||
|     Time d = +a; | ||||
| 
 | ||||
|     cout << c.minutes << " " << c.seconds << endl; | ||||
|     cout << d.minutes << " " << d.seconds << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
| 
 | ||||
|     Задача: | ||||
| 
 | ||||
|         1)  Что если операторы сложения поменяются местами | ||||
|                 Time b = 90 + a; | ||||
|             Сработает ли в этом случае наша функция operator+ и, если нет, что нужно добавить, чтобы такое сложение сработало? | ||||
|          | ||||
| 
 | ||||
|         2)  Напишите перегруженный оператор, который будет складывать не время и число, а два времени | ||||
| 
 | ||||
|                 Time operator+(Time ta, Time tb) | ||||
| 
 | ||||
| 
 | ||||
|          | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,38 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| /*
 | ||||
|     В прошлом семестре, для хранения результатов логических операций, мы использовали целочисленные типы (например int). | ||||
|      | ||||
|     В языке C++ есть встроенный тип bool, который может принимать 2 значения (true и false). | ||||
|     Для хранения значения логических переменных желательно использовать этот тип | ||||
| 
 | ||||
|      | ||||
|     При печати на экран с помощью std::cout переменных типа bool печатается либо 0 либо 1 | ||||
|     Чтобы на экран печаталось false или true нужно в std::cout передать специальный объект std::boolalpha  | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| bool isEven(int a) | ||||
| { | ||||
|     return a % 2 == 0; | ||||
| } | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     bool a = isEven(10); | ||||
|     bool b = isEven(15); | ||||
|     bool c = a || b; | ||||
| 
 | ||||
| 
 | ||||
|     if (c) | ||||
|         cout << "Yes" << endl; | ||||
|     else | ||||
|         cout << "No" << endl; | ||||
| 
 | ||||
|     cout << c << endl; | ||||
|     cout << std::boolalpha << c << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,68 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Помимо арифметических операторов можно перегружать и операторы сравнения (и многие другие операторы) | ||||
|     Желательно, чтобы операторы сравнения возвращали bool | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| struct Time  | ||||
| { | ||||
|     int minutes; | ||||
|     int seconds; | ||||
| }; | ||||
| 
 | ||||
| Time operator+(Time ta, Time tb) | ||||
| { | ||||
|     Time result = ta; | ||||
|     result.seconds += 60 * tb.minutes + tb.seconds; | ||||
|      | ||||
|     result.minutes += (result.seconds / 60); | ||||
|     result.seconds %= 60; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool operator>(Time ta, Time tb) | ||||
| { | ||||
|     bool result = false; | ||||
| 
 | ||||
|     if (ta.minutes > tb.minutes) | ||||
|         result = true; | ||||
|     else if (ta.minutes == tb.minutes && ta.seconds > tb.seconds) | ||||
|         result = true; | ||||
|      | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Time a = {10, 20}; | ||||
|     Time b = {10, 40}; | ||||
|     Time c = {0,  20}; | ||||
| 
 | ||||
|     cout << std::boolalpha; | ||||
|     cout << (a > b) << endl; | ||||
|     cout << (b > a) << endl; | ||||
|     cout << (a + c > b) << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
| 
 | ||||
|     Задача: | ||||
| 
 | ||||
|         1)  Заметьте, что при выводе на экран сравнение было взято в скобки | ||||
|                 cout << (a > b) << endl; | ||||
| 
 | ||||
|             Что будет, если эти скобки не писать и почему | ||||
|                 cout << a > b << endl; | ||||
|          | ||||
|          | ||||
|         2)  Напишите перегруженные операторы <  >=  <=  ==  !=  для сравнения объектов структур типа Time друг с другом | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,110 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Помимо арифметических операторов можно перегружать и операторы сравнения (и многие другие операторы) | ||||
|     Желательно, чтобы операторы сравнения возвращали bool | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| struct Time  | ||||
| { | ||||
|     int minutes; | ||||
|     int seconds; | ||||
| }; | ||||
| 
 | ||||
| Time operator+(Time ta, Time tb) | ||||
| { | ||||
|     Time result = ta; | ||||
|     result.seconds += 60 * tb.minutes + tb.seconds; | ||||
|      | ||||
|     result.minutes += (result.seconds / 60); | ||||
|     result.seconds %= 60; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool operator>(Time ta, Time tb) | ||||
| { | ||||
|     bool result = false; | ||||
| 
 | ||||
|     if (ta.minutes > tb.minutes) | ||||
|         result = true; | ||||
|     else if (ta.minutes == tb.minutes && ta.seconds > tb.seconds) | ||||
|         result = true; | ||||
|      | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool operator==(Time ta, Time tb) | ||||
| { | ||||
|     bool result = false; | ||||
|     if (ta.minutes == tb.minutes && ta.seconds == tb.seconds) | ||||
|         result = true; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| bool operator!=(Time ta, Time tb) | ||||
| { | ||||
|     return !(ta == tb); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool operator>=(Time ta, Time tb) | ||||
| { | ||||
|     return ta > tb || ta == tb; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool operator<(Time ta, Time tb) | ||||
| { | ||||
|     return !(ta >= tb); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool operator<=(Time ta, Time tb) | ||||
| { | ||||
|     return !(ta > tb); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Time a = {10, 20}; | ||||
|     Time b = {10, 40}; | ||||
|     Time c = {0,  20}; | ||||
| 
 | ||||
|     cout << std::boolalpha; | ||||
|     cout << (a == b) << endl; | ||||
|     cout << (a != b) << endl; | ||||
| 
 | ||||
|     cout << (a < b) << endl; | ||||
|     cout << (a <= b) << endl; | ||||
|     cout << (a > b) << endl; | ||||
|     cout << (a >= b) << endl; | ||||
|     cout << (a + c >= b) << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
| 
 | ||||
|     Задача: | ||||
| 
 | ||||
|         1)  Заметьте, что при выводе на экран сравнение было взято в скобки | ||||
|                 cout << (a > b) << endl; | ||||
| 
 | ||||
|             Что будет, если эти скобки не писать и почему | ||||
|                 cout << a > b << endl; | ||||
|              | ||||
|             Ошибка происходит из-за того, что приоритет операции << выше, чем у операций сравнения | ||||
|             В результате сначала проводится | ||||
|                 cout << a | ||||
|             затем получившийся объект сравнивается с b. Это и приводит к ошибке. | ||||
| */ | ||||
|  | @ -0,0 +1,49 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| /*
 | ||||
|     Перегрузка оператора << для вывода на экран | ||||
| 
 | ||||
|     Напомним, что объект под названием cout имеет тип ostream (сокращение от output stream - выходной поток) | ||||
|     и хранится в библиотеке iostream в пространстве имён std | ||||
| 
 | ||||
|     То есть где-то внутри библиотеки iostream объявлена глобальная переменная по имени cout типа ostream | ||||
|         ostream cout; | ||||
| 
 | ||||
|      | ||||
|     Мы можем перегрузить оператор << с первым аргументом типа std::ostream, а вторым аргументом - нашим типом, | ||||
|     чтобы удобно выводить на экран объекты нашего типа. | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| struct Time  | ||||
| { | ||||
|     int minutes; | ||||
|     int seconds; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| void operator<<(std::ostream& out, Time t) | ||||
| { | ||||
|     out << t.minutes << ":" << t.seconds; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Time a = {10, 20}; | ||||
|     cout << a; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задача: | ||||
| 
 | ||||
|         cout << a;  работает, но | ||||
|         cout << a << endl; выдаёт ошибку в данной программе. | ||||
| 
 | ||||
|         Из-за чего это происходит и как исправить эту ошибку? | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,63 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| struct Time  | ||||
| { | ||||
|     int minutes; | ||||
|     int seconds; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| Time operator+(Time ta, Time tb) | ||||
| { | ||||
|     Time result = ta; | ||||
|     result.seconds += 60 * tb.minutes + tb.seconds; | ||||
|      | ||||
|     result.minutes += (result.seconds / 60); | ||||
|     result.seconds %= 60; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Time t) | ||||
| { | ||||
|     out << t.minutes << ":" << t.seconds; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Time a = {10, 20}; | ||||
|     Time b = {15, 50}; | ||||
| 
 | ||||
|     cout << a << endl << b << endl; | ||||
|     cout << a + b << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задача: | ||||
| 
 | ||||
|         cout << a;  работает, но | ||||
|         cout << a << endl; выдаёт ошибку в данной программе. | ||||
| 
 | ||||
|         Из-за чего это происходит и как исправить эту ошибку? | ||||
| 
 | ||||
| 
 | ||||
|     Решение: | ||||
| 
 | ||||
|         Ошибка происходила из-за того, что оператор << ничего не возвращал. | ||||
|          | ||||
|         В строке   cout << a << endl; | ||||
|         результат  cout << a  был void и к нему нельзя применить оператор << ещё раз. | ||||
| 
 | ||||
| 
 | ||||
|         Результат  cout << a  должен быть тоже быть равен cout | ||||
|         Но, поскольку глобальный объект cout копировать мы не можем, у нас остаётся единственный выход: | ||||
|         принимать и возвращать объект cout по ссылке. | ||||
| 
 | ||||
| */   | ||||
|  | @ -0,0 +1,52 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| struct Complex  | ||||
| { | ||||
|     float re, im; | ||||
| }; | ||||
| 
 | ||||
| Complex operator+(Complex first, Complex second)  | ||||
| { | ||||
|     Complex result = {first.re + second.re, first.im + second.im}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Complex z1 = {3, 7}; | ||||
|     Complex z2 = {2, -4}; | ||||
| 
 | ||||
|     Complex z = z1 + z2;  | ||||
|     cout << z.re << " + " << z.im << "i" << endl; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|         1) Перегрузите следующие операторы: | ||||
|             - Вычитание | ||||
|             - Умножение | ||||
|             - Деление | ||||
|             - Унарный минус | ||||
|             - Унарный плюс | ||||
|             - Сравнение == | ||||
|             - Сопряжение - это операция, которая меняет знак мнимой части комплексного числа | ||||
|               Для сопряжения используйте оператор унарная звёздочка * | ||||
| 
 | ||||
|         2) Перегрузите оператор вывода << | ||||
| 
 | ||||
|         3) Напишите функцию exp(z) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     /*
 | ||||
|         cout << z1 - z2 << endl; | ||||
|         cout << z1 * z2 << endl; | ||||
|         cout << z1 / z2 << endl; | ||||
|         cout << -z1 << endl; | ||||
|         cout << *z1 << endl;    // (Комплексно-сопряжённое)
 | ||||
| 
 | ||||
|         z = exp(z1 + z2)/(z1 * z2); | ||||
|         cout << z << endl; | ||||
|     */ | ||||
|  | @ -0,0 +1,52 @@ | |||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     В библиотеки iomanip содержатся специальные функции, для работы с потоками ostream | ||||
| 
 | ||||
|         setw  -  установить минимальный размер в символах для печати следующего объекта | ||||
|         setfill  -  если размер печати меньше минимального, то замостить оставшееся соответствующим символом | ||||
| 
 | ||||
|         setprecision  -  установить точность (для вещественных чисел) | ||||
| */   | ||||
| 
 | ||||
| 
 | ||||
| struct Time  | ||||
| { | ||||
|     int minutes; | ||||
|     int seconds; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| Time operator+(Time ta, Time tb) | ||||
| { | ||||
|     Time result = ta; | ||||
|     result.seconds += 60 * tb.minutes + tb.seconds; | ||||
|      | ||||
|     result.minutes += (result.seconds / 60); | ||||
|     result.seconds %= 60; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Time t) | ||||
| { | ||||
|     out << std::setfill('0') << std::setw(2) << t.minutes << ":" <<  | ||||
|            std::setfill('0') << std::setw(2) << t.seconds; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Time a = {1, 5}; | ||||
|     Time b = {4, 20}; | ||||
| 
 | ||||
|     cout << a << endl << b << endl; | ||||
|     cout << a + b << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,52 @@ | |||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     В отличии от языка C, язык C++ не делает неявное преобразование типов указателей. | ||||
| 
 | ||||
|     Рассмотрим, например, код: | ||||
| 
 | ||||
|         int a = 10; | ||||
|         char* p = &a; | ||||
| 
 | ||||
|     В языке C такой код сработает, несмотря на то, что в строке  char* p = &a;  слева стоит указатель типа char* | ||||
|     а справа объект типа int*. Будет произведено неявное преобразование типов указателей. | ||||
| 
 | ||||
|     В языке C++ такой код приведёт к ошибке, так как C++ не преобразует указатели неявно. | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     Рассмотрим, например, код: | ||||
| 
 | ||||
|         int* q = malloc(10 * sizeof(int)); | ||||
| 
 | ||||
|     В языке C такой код сработает, несмотря на то, что слева стоит указатель типа int* | ||||
|     а справа объект типа void* (malloc возвращает указатель типа void*).  | ||||
|     Будет произведено неявное преобразование типов указателей. | ||||
| 
 | ||||
|     В языке C++ такой код приведёт к ошибке, так как C++ не преобразует указатели неявно. | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
|     int a = 10; | ||||
|     char* p = &a; | ||||
| 
 | ||||
| 
 | ||||
|     int* q = malloc(10 * sizeof(int)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
| 
 | ||||
|     Задача: | ||||
| 
 | ||||
|     Исправьте ошибки компиляции, явно приведя указатель к правильным типам.  | ||||
| 
 | ||||
| */ | ||||
|  | @ -0,0 +1,13 @@ | |||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
|     int a = 10; | ||||
|     char* p = (char*)&a; | ||||
| 
 | ||||
| 
 | ||||
|     int* q = (int*)malloc(10 * sizeof(int)); | ||||
| } | ||||
|  | @ -0,0 +1,17 @@ | |||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     В языке C++ желательно использовать более безопасное приведение типов static_cast | ||||
| */ | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
|     int a = 10; | ||||
|     char* p = static_cast<char*>(&a); | ||||
| 
 | ||||
| 
 | ||||
|     int* q = static_cast<int*>(malloc(10 * sizeof(int))); | ||||
| } | ||||
							
								
								
									
										50
									
								
								seminar01_overload/classroom_tasks/code/04other/01nulptr.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								seminar01_overload/classroom_tasks/code/04other/01nulptr.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| #include <cstdio> | ||||
| 
 | ||||
| /*
 | ||||
|     Новое специальное нулевое значение для указателя: nullptr | ||||
|     В языке C для этой цели использовался NULL, который был просто числом 0 | ||||
| 
 | ||||
|     Если определить NULL так:   | ||||
| 
 | ||||
|         #define NULL (void*)0 | ||||
| 
 | ||||
|     То, в отличии от языка C, в языке C++ простая строка вида: | ||||
| 
 | ||||
|         int* p = NULL; | ||||
| 
 | ||||
|     не сработает, так как слева стоит int* а справа void*  | ||||
| 
 | ||||
|      | ||||
|     Если определить NULL так:   | ||||
| 
 | ||||
|         #define NULL 0 | ||||
| 
 | ||||
|     то в C++ могут возникнуть проблемы с перегрузкой, как это показано ниже. | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| void print(int value)  | ||||
| { | ||||
|     printf("Int: %d\n", value); | ||||
| } | ||||
| 
 | ||||
| void print(void* pointer)  | ||||
| { | ||||
|     printf("Pointer: %p\n", pointer); | ||||
| } | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     void* p1 = NULL; | ||||
|     void* p2 = nullptr; | ||||
| 
 | ||||
|     // Всё ОК (компилятор может выбрать функцию):
 | ||||
|     print(p1); | ||||
|     print(p2); | ||||
| 
 | ||||
|     // Тут неверно (компилятор не может выбрать перегруженную функцию, произойдёт ошибка):
 | ||||
|     print(NULL); | ||||
| 
 | ||||
|     // Тут всё OK:
 | ||||
|     print(nullptr); | ||||
| } | ||||
|  | @ -0,0 +1,42 @@ | |||
| #include <iostream> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| /*
 | ||||
|     В отличии от языка C, в C++ можно задавать значения по умолчанию | ||||
|     для аргументов функций | ||||
| 
 | ||||
|     Функцию printSquare можно вызвать с одним, двумя или тремя | ||||
|     параметрами. Аргументы width и height будут заданы аргументами по умолчанию. | ||||
|     Если передаваемых аргументов будет меньше трёх. | ||||
| */ | ||||
| 
 | ||||
| void printSquare(char c, int width = 10, int height = 5)  | ||||
| { | ||||
|     for (int i = 0; i < width; i++)  | ||||
|     { | ||||
|         for (int j = 0; j < height; j++)  | ||||
|         { | ||||
|             cout << c; | ||||
|         } | ||||
|         cout << endl; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     printSquare('+', 6, 4); | ||||
|     printSquare('#', 15); | ||||
|     printSquare('O'); | ||||
|      | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задание: | ||||
| 
 | ||||
|     1) Написать функцию: | ||||
|         void print(char str[], bool isCapitalized = false) | ||||
|         Которая будет просто печатать строку str, если isCapitalized = false, | ||||
|         а если isCapitalized = true, то будет печатать всю строку в верхнем регистре | ||||
| */ | ||||
		Reference in a new issue