This commit is contained in:
nihonium 2022-09-14 19:05:27 +03:00
parent 46d1c64684
commit ab6732eded
Signed by: nihonium
GPG key ID: 0251623741027CFC
98 changed files with 10319 additions and 0 deletions

View file

@ -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,
которая будет принимать точку по указателю и делить координаты точки на норму точки
Эта функция не должна ничего возвращать
*/

View file

@ -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);
}

View file

@ -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
*/

View file

@ -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;
}

View file

@ -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?
*/

View file

@ -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;
}

View file

@ -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
*/