-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexplanations.txt
More file actions
109 lines (83 loc) · 7.9 KB
/
explanations.txt
File metadata and controls
109 lines (83 loc) · 7.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
Конструктор по умолчанию Когда создаёте объект без аргументов
Копирующий конструктор Когда создаёте новый объект из существующего
Оператор присваивания копированием Когда уже созданному объекту присваиваете другой
Деструктор Когда объект уничтожается
Destructor: is called
1) Automatically when the object goes out of scope
2) When you call delete on a pointer to the object
Prevents resource leaks.
You return the book when you're done
Copy Constructor (ClassName(const ClassName& other)) is called
1) when we write ClassName b = a;
If your class contains raw pointers, default copy will copy the pointer,
not the data (shallow copy) → both objects now share the same memory, which causes bugs on deletion.
You photocopy the book and give a new copy to someone
Copy Assignment Operator (ClassName& operator=(const ClassName& other)) is called
1) when you write a = b; and both a and b already exist
You already have a book, but replace it with a photocopy of another
Точность (accuracy) — это насколько близко значение к истинному.
Прецизионность (precision) — это насколько подробно известно значение, насколько точно оно определено.
Int values: good accuracy + limited precision (whole numbers are perfect, can't represent 2.5 or 1/3)
Float values: bad accuracy + good precision
Float:
32 бита разделены на три части:
-S (1 бит) для хранения знака
-E (8 бит) для экспоненты (window = interval between neighbor powers of 2)
-M (23 бита) для мантиссы (offset within this window)
В IEEE-754 мантисса интерпретируется как дробь с подразумеваемой "1" слева от десятичной точки.
число = (знак ? -1 : 1) * 2^(экспонента) * 1.(биты мантиссы)
Смещение разделяет окно на $2^{23} = 8388608 сегментов.
С помощью окна и смещения можно аппроксимировать число.
Давайте возьмём ещё один пример с подробным вычислением представлением в виде числа с плавающей точкой хорошо известного всем нам значения: 3,14.
Число 3,14 положительно $\rightarrow S=0$.
Число 3,14 находится между степенями двойки 2 и 4, то есть окно числа с плавающей запятой должно начинаться с $2^1$ $\rightarrow E=128$ (см. формулу, где окно — это $2^{(E-127)}$).
Наконец, есть $2^{23}$ смещений, которыми можно выразить расположение 3,14 внутри интервала [2-4]. Оно находится в $\frac{3,14 -2 }{4 - 2} = 0,57$ внутри интервала, что даёт нам смещение $M = 2^{23}*0,57 = 4781507$
В двоичном виде это преобразуется в следующее:
S = 0 = 0b
E = 128 = 10000000
M = 4781507 = 10010001111010111000011
Двоичное представление с плавающей точкой числа 3,14.
То есть значение 3,14 аппроксимируется как 3,1400001049041748046875.
#define EPSILON 1.0e-7
#define flt_equals(a, b) (fabs((a)-(b)) < EPSILON)
Проблема "ромбовидного наследования" (Diamond Problem)
И и ScavTrap, и FragTrap наследуют от ClapTrap.
А потом DiamondTrap наследует оба класса. Получается:
💥 В классе DiamondTrap будет две копии ClapTrap → одна от ScavTrap, вторая от FragTrap.
Это приводит к двусмысленности:
DiamondTrap dt("Bot");
dt._hitPoints; // ❌ ошибка: из какого ClapTrap брать — из ScavTrap или FragTrap?
Чтобы избежать дублирования базового класса, C++ предоставляет виртуальное наследование
class ScavTrap : virtual public ClapTrap { ... };
class FragTrap : virtual public ClapTrap { ... };
Это говорит компилятору:
«Если кто-то унаследует оба (и ScavTrap, и FragTrap), то базовый класс ClapTrap нужно создать один раз, и он будет общий».
Так как ClapTrap виртуально наследуется, ответственность за его инициализацию ложится на самого нижнего наследника — то есть на DiamondTrap.
Virtual Это говорит компилятору:
⚠️ "Я не хочу создавать свою копию ClapTrap, если кто-то будет использовать меня в множественном наследовании. Пусть создаёт тот, кто будет последним в иерархии."
Полиморфизм подтипов означает, что указатель (или ссылка) на базовый класс может указывать на объект производного класса
Animal* animal = new Dog();
animal->speak(); // Выведет: Dog barks
Animal* — указатель на базовый тип, но поведение зависит от реального объекта (Dog)
Абстрактный класс — это класс, от которого нельзя создать объект напрямую, потому что он содержит хотя бы одну чисто виртуальную функцию.
Такой класс используется как базовый интерфейс, а производные классы должны реализовать чисто виртуальные функции.
Интерфейс — это класс, содержащий только чисто виртуальные функции и не имеющий данных/реализаций.
В C++ отдельного ключевого слова interface нет, но интерфейсы реализуются через абстрактные классы.
Название интерфейсов часто начинается с I, например IShape, IDrawable
virtual void attack(const std::string& target) = 0;
Это называется чисто виртуальная функция
"= 0" говорит компилятору: в этом классе нет реализации этого метода, её должны дать потомки
ScavTrap bob("Bob");
FragTrap joe("Joe");
ClapTrap* ptr = &bob;
ptr->attack("target"); // вызовется ScavTrap::attack()
ptr = &joe;
ptr->attack("target"); // вызовется FragTrap::attack()
deep copy (глубокое копирование) и shallow copy (поверхностное копирование)
Shallow copy (поверхностное копирование)
Копирует значения полей объекта "как есть", включая указатели.
В результате два объекта указывают на одну и ту же область памяти.
Изменение данных через один объект влияет на другой.
Deep copy (глубокое копирование)
Создаёт новый объект и новую копию всех данных, на которые указывают
указатели. Каждый объект имеет свои независимые данные.