seminar2
This commit is contained in:
		
							parent
							
								
									46d1c64684
								
							
						
					
					
						commit
						ab6732eded
					
				
					 98 changed files with 10319 additions and 0 deletions
				
			
		|  | @ -0,0 +1,56 @@ | |||
| /*
 | ||||
|     Это программа на языке C, для компиляции: | ||||
|         gcc 00point.c | ||||
|         ./a.out | ||||
| 
 | ||||
|     Опишем структуру точки в двумерном пространстве на языке C | ||||
| 
 | ||||
|     Точка задаётся двумя координатами x и y | ||||
|     Так как эта структура имеет очень маленький размер (всего 8 байт), то в функции | ||||
|     её можно передавать по значению, а не по константному указателю. | ||||
| */ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <math.h> | ||||
| 
 | ||||
| struct point  | ||||
| { | ||||
|     float x, y; | ||||
| }; | ||||
| typedef struct point Point; | ||||
| 
 | ||||
| 
 | ||||
| void point_print(Point a) | ||||
| { | ||||
|     printf("(%.2f, %.2f)\n", a.x, a.y); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Point a = {7.2, 3.1}; | ||||
|     Point b = {-4.6, 2.4}; | ||||
|      | ||||
|     point_print(a); | ||||
|     point_print(b); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
|      | ||||
|         1)  Напишите функцию point_add,  | ||||
|             которая будет принимать две точки и возвращать их сумму | ||||
| 
 | ||||
|         2)  Напишите функцию point_norm,  | ||||
|             которая будет принимать точку и возвращать расстояние до этой точки от начала координат | ||||
|             Будем называть расстояние от точки до начала координат нормой точки | ||||
|             Для вычисления корня числа можно использовать функцию sqrt из math.h | ||||
| 
 | ||||
|         3)  Напишите функцию point_mult,  | ||||
|             которая будет принимать на вход точку и число k типа float и возвращать точку, координаты которой | ||||
|             равны координатам изначальной точки, умноженные на число k | ||||
| 
 | ||||
|         4)  Напишите функцию point_normalize, | ||||
|             которая будет принимать точку по указателю и делить координаты точки на норму точки | ||||
|             Эта функция не должна ничего возвращать | ||||
| */ | ||||
|  | @ -0,0 +1,63 @@ | |||
| /*
 | ||||
|     Это программа на языке C, для компиляции: | ||||
|         gcc 00point_solution.c | ||||
|         ./a.out | ||||
| */ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <math.h> | ||||
| 
 | ||||
| 
 | ||||
| struct point  | ||||
| { | ||||
|     float x, y; | ||||
| }; | ||||
| typedef struct point Point; | ||||
| 
 | ||||
| 
 | ||||
| void point_print(Point a) | ||||
| { | ||||
|     printf("(%.2f, %.2f)\n", a.x, a.y); | ||||
| } | ||||
| 
 | ||||
| Point point_add(Point a, Point b) | ||||
| { | ||||
|     Point result = {a.x + b.x, a.y + b.y}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| float point_norm(Point a) | ||||
| { | ||||
|     return sqrtf(a.x * a.x + a.y * a.y); | ||||
| } | ||||
| 
 | ||||
| Point point_mult(Point a, float k) | ||||
| { | ||||
|     Point result = {k * a.x, k * a.y}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| void point_normalize(Point* pa) | ||||
| { | ||||
|     float norm = point_norm(*pa); | ||||
|     pa->x /= norm; | ||||
|     pa->y /= norm; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Point a = {7.2, 3.1}; | ||||
|     Point b = {-4.6, 2.4}; | ||||
|      | ||||
|     point_print(a); | ||||
|     point_print(b); | ||||
| 
 | ||||
|     Point c = point_add(a, b); | ||||
|     point_print(c); | ||||
| 
 | ||||
|     point_print(point_mult(c, 1.5f)); | ||||
| 
 | ||||
|     point_normalize(&c); | ||||
|     point_print(c); | ||||
| } | ||||
|  | @ -0,0 +1,84 @@ | |||
| /*
 | ||||
|     Это программа на языке C++, для компиляции: | ||||
|         g++ 01point.cpp | ||||
| 
 | ||||
|     Та же самая точка, но на языке C++ | ||||
| 
 | ||||
|     В этом файле была видоизменена программа из предыдущего файла. | ||||
|     Были использованы перегруженные операторы для более удобного сложения и умножения точек. | ||||
|     Также была использована ссылка вместо указателя в функции pointNormalize. | ||||
| */ | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <cmath> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| struct Point  | ||||
| { | ||||
|     float x, y; | ||||
| }; | ||||
| 
 | ||||
| void pointPrint(Point a) | ||||
| { | ||||
|     cout << std::setprecision(2) << "(" << a.x << ", " << a.y << ")" << endl; | ||||
| } | ||||
| 
 | ||||
| Point operator+(Point a, Point b) | ||||
| { | ||||
|     Point result = {a.x + b.x, a.y + b.y}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| float pointNorm(Point a) | ||||
| { | ||||
|     return std::sqrt(a.x * a.x + a.y * a.y); | ||||
| } | ||||
| 
 | ||||
| Point operator*(Point a, float k) | ||||
| { | ||||
|     Point result = {k * a.x, k * a.y}; | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| void pointNormalize(Point& a) | ||||
| { | ||||
|     float norm = pointNorm(a); | ||||
|     a.x /= norm; | ||||
|     a.y /= norm; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Point a = {7.2, 3.1}; | ||||
|     Point b = {-4.6, 2.4}; | ||||
|      | ||||
|     pointPrint(a); | ||||
|     pointPrint(b); | ||||
| 
 | ||||
|     Point c = a + b; | ||||
|     pointPrint(c); | ||||
| 
 | ||||
|     pointPrint(c * 1.5f); | ||||
| 
 | ||||
|     pointNormalize(c); | ||||
|     pointPrint(c); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задача: | ||||
| 
 | ||||
|         1)  Инкапсулируйте функции operator+, pointNorm, operator* и pointNormalize | ||||
|             Их нужно сделать методами, то есть положить внутрь структуры Point | ||||
|             Не забудьте сделать соответствующие методы константными | ||||
| 
 | ||||
|         2)  Можно сделать то же самое с функцией printPoint, а можно поступить по-другому | ||||
|             и перегрузить оператор << для типов std::ostream и Point | ||||
| */ | ||||
|  | @ -0,0 +1,97 @@ | |||
| /*
 | ||||
|     Обратите внимание на следующие моменты в этом решении: | ||||
| 
 | ||||
|     1)  При переносе функций внутрь класса у них стало на 1 аргумент меньше | ||||
|         Просто потому что все методы неявно принимают вызывающий их объект | ||||
| 
 | ||||
|         Например, если a это точка, то при вызове: | ||||
|             a.norm() | ||||
|          | ||||
|         метод norm 'знает', что его вызвала имено точка a и может доступаться до её полей x и y | ||||
| 
 | ||||
| 
 | ||||
|     2)  Перегруженные операторы тоже могут быть методами | ||||
|         При этом оператор преобразуется следующим образом: | ||||
| 
 | ||||
|         a @ b   ->   a.operator@(b) | ||||
|         где на месте @ может быть любой бинарный оператор | ||||
| 
 | ||||
|         Например, сложение преобразуется так: | ||||
|         a + b   ->   a.operator+(b) | ||||
| 
 | ||||
|         Обратите внимание, что перегруженный оператор может стать методом только первого аргумента | ||||
| 
 | ||||
| 
 | ||||
|     3)  Перегрузка оператора << для типов std::ostream и Point | ||||
|         Для более удобного вывода на экран можно перегрузить этот оператор | ||||
| 
 | ||||
|         Когда компилятор встретит выражение     cout << a    где cout имеет тип std::ostream, а имеет тип Point | ||||
|         то он вызовет эту функцию. | ||||
|         Эта функция должна вызывать ссылку на cout так как результатом   cout << a   тоже должен быть cout | ||||
|         чтобы мы могли выводить цепочкой, например так:   cout << a << b << endl | ||||
| */ | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <cmath> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| struct Point  | ||||
| { | ||||
|     float x, y; | ||||
| 
 | ||||
|     Point operator+(Point b) const | ||||
|     { | ||||
|         Point result = {x + b.x, y + b.y}; | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     float norm() const | ||||
|     { | ||||
|         return std::sqrt(x * x + y * y); | ||||
|     } | ||||
| 
 | ||||
|     Point operator*(float k) const | ||||
|     { | ||||
|         Point result = {k * x, k * y}; | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     void normalize() | ||||
|     { | ||||
|         float normv = norm(); | ||||
|         x /= normv; | ||||
|         y /= normv; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Point a) | ||||
| { | ||||
|     out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")"; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Point a = {7.2, 3.1}; | ||||
|     Point b = {-4.6, 2.4}; | ||||
|      | ||||
|     cout << a << endl; | ||||
|     cout << b << endl; | ||||
| 
 | ||||
|     Point c = a + b; | ||||
|     cout << c << endl; | ||||
| 
 | ||||
|     cout << c * 1.5f << endl; | ||||
| 
 | ||||
|     c.normalize(); | ||||
|     cout << c << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,48 @@ | |||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <cmath> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| struct Point  | ||||
| { | ||||
|     float x, y; | ||||
| 
 | ||||
|     Point operator*(float k) const | ||||
|     { | ||||
|         Point result = {k * x, k * y}; | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Point a) | ||||
| { | ||||
|     out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")"; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Point a = {2.1, 1.5}; | ||||
|      | ||||
|     cout << a * 2 << endl; | ||||
|     cout << 2 * a << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задачи: | ||||
| 
 | ||||
|         1)  В этой программе выражение  a * 2  вычисляется правильно, но | ||||
|                              выражение  2 * a  даёт ошибку. | ||||
| 
 | ||||
|             Из-за чего это происходит? Исправьте ситуацию так, чтобы выражение 2 * a также вычислялось. | ||||
| 
 | ||||
| 
 | ||||
|         2)  Можно ли сделать перегруженный оператор << методом класса Point? | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,64 @@ | |||
| /*
 | ||||
|     Решения: | ||||
| 
 | ||||
|         1)  Выражение  a * 2  вычисляется так как есть перегруженный оператор a.operator*(2) | ||||
|             Выражение  2 * a  даёт ошибку так как не было перегруженного оператора operator*(2, a) | ||||
| 
 | ||||
|             Но его можно просто написать, как это сделано ниже. | ||||
| 
 | ||||
|             Сделать этот оператор методом мы не можем, так как перегруженный оператор может быть методом | ||||
|             только первого аргумента, первый аргумент в данном случае это число целочисленного типа float. | ||||
|             Добавить метод в тип float мы не можем, так как float это вообще не класс. | ||||
| 
 | ||||
|             Замечание: Литерал 2 на самом деле имеет тип int, но int может конвертироваться во float если нужно  | ||||
| 
 | ||||
| 
 | ||||
|         2)  Можно ли сделать перегруженный оператор << методом класса Point? | ||||
| 
 | ||||
|             Нет, нельзя. Перегруженный оператор может быть методом только первого аргумента. | ||||
| */ | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <iomanip> | ||||
| #include <cmath> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| struct Point  | ||||
| { | ||||
|     float x, y; | ||||
| 
 | ||||
|     Point operator*(float k) const | ||||
|     { | ||||
|         Point result = {k * x, k * y}; | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| Point operator*(float k, Point a) | ||||
| { | ||||
|     return a * k; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, Point a) | ||||
| { | ||||
|     out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")"; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     Point a = {2.1, 1.5}; | ||||
|      | ||||
|     cout << a * 2 << endl; | ||||
|     cout << 2 * a << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,124 @@ | |||
| /*
 | ||||
|     До этого момента поля x и y класса Point были публичными | ||||
| 
 | ||||
|     Обычно, мы не хотим делать поля публичными, так как мы не хотим, чтобы поля могли бы быть заданы некоректным значением извне класса. | ||||
|     Однако, в случае класса Point некорректных значений для x и y просто не существует - любое вещественное число будет | ||||
|     корректным для значения координаты точки. | ||||
|     Поэтому нет ничего плохого, чтобы сделать x и y публичными для класса Point | ||||
| 
 | ||||
| 
 | ||||
|     Но давайте сделаем класс с немного более сложным поведением. | ||||
|     Точка RestrictedPoint - это будет точка, которая может находится только в квадрате [0,1]x[0,1] | ||||
|     То есть поле x может принимать значения только от 0 до 1 и поле y может принимать значения только от 0 до 1. | ||||
| 
 | ||||
|     Сделаем поля x и y приватными (и назовём их mx и my) | ||||
|     Теперь до них можно будет доступиться только в методах класса RestrictedPoint и в друзьях. | ||||
|      | ||||
|     Чтобы можно было работать с этими полями вне класса напишем методы | ||||
|         getx, gety, setx, sety | ||||
|     Такие методы для получения полей и записи в поля класса называются геттерами и сеттерами | ||||
|     Функции getx и gety просто возвращают соответствующие координаты | ||||
|     Функции setx и sety меняют соответствующие координаты и следят, чтобы они находились в диапазоне от 0 до 1 | ||||
| 
 | ||||
| 
 | ||||
|     Нам понадобится стандартная функция std::clamp из <algorithm>, которая принимает на вход три числа и | ||||
|         если первое число находится в промежутке между вторым и третьим, то clamp возвращает первое число | ||||
|         если первое число меньше, чем второе, то clamp возвращает второе число | ||||
|         если первое число больше, чем третье, то clamp возвращает третье число | ||||
|     Грубо говоря clamp ограничивает число в заданых пределах | ||||
| */ | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <cmath> | ||||
| #include <algorithm> | ||||
| using std::cout, std::endl; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| class RestrictedPoint  | ||||
| { | ||||
| private: | ||||
|     float mx, my; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     RestrictedPoint(float x, float y) | ||||
|     { | ||||
|         mx = std::clamp(x, 0.0f, 1.0f); | ||||
|         my = std::clamp(y, 0.0f, 1.0f); | ||||
|     } | ||||
| 
 | ||||
|     RestrictedPoint() | ||||
|     { | ||||
|         mx = 0; | ||||
|         my = 0; | ||||
|     } | ||||
| 
 | ||||
|     float getx() const  | ||||
|     { | ||||
|         return mx; | ||||
|     } | ||||
| 
 | ||||
|     float gety() const  | ||||
|     { | ||||
|         return my; | ||||
|     } | ||||
| 
 | ||||
|     void setx(float x)  | ||||
|     { | ||||
|         mx = std::clamp(x, 0.0f, 1.0f); | ||||
|     } | ||||
| 
 | ||||
|     void sety(float y)  | ||||
|     { | ||||
|         my = std::clamp(y, 0.0f, 1.0f); | ||||
|     } | ||||
| 
 | ||||
|     float norm() const  | ||||
|     { | ||||
|         return std::sqrt(mx*mx + my*my); | ||||
|     } | ||||
| 
 | ||||
|     RestrictedPoint operator+(const RestrictedPoint& right) const  | ||||
|     { | ||||
|         RestrictedPoint result; | ||||
|         result.mx = std::clamp(mx + right.mx, 0.0f, 1.0f); | ||||
|         result.my = std::clamp(my + right.my, 0.0f, 1.0f); | ||||
|         return result; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, const RestrictedPoint& a)  | ||||
| { | ||||
|     out << "(" << a.getx() << ", " << a.gety() << ")"; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     RestrictedPoint a = RestrictedPoint(0.5, 1.2); | ||||
|     cout << a << endl; | ||||
| 
 | ||||
|     a.setx(2); | ||||
|     cout << a << endl; | ||||
| 
 | ||||
|     a.sety(-5); | ||||
|     cout << a << endl; | ||||
| 
 | ||||
| 
 | ||||
|     RestrictedPoint b = RestrictedPoint(0.4, 0.2); | ||||
|     RestrictedPoint c = RestrictedPoint(0.8, 0.4); | ||||
|     cout << c + b << endl; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|     Задача: | ||||
| 
 | ||||
|         1)  Добавьте к классу RestrictedPoint оператор умножения на число типа float | ||||
| 
 | ||||
| */ | ||||
		Reference in a new issue