Added 06.md

This commit is contained in:
thematdev 2023-10-09 20:00:51 +03:00
parent 6228e4a161
commit 5e199a9c83
Signed by: thematdev
GPG Key ID: D12878639B090D90

196
pages/mipt_cxx1/06.md Normal file
View File

@ -0,0 +1,196 @@
## 2.7 Type conversions
`static_cast` -- ключевое слово языка C++
```C++
T x;
static_cast<U>(x);
```
С помощью него неявные преобразования можно сделать явно через `static_cast`,
такие как `double -> int, A* -> void*`.
`reinterpret_cast` -- говорит компилятору трактовать
переменную `x` как переменную типа `U` побитово. То
есть интерпретировать память как будто бы там лежит
другой тип.
1. `reinterpret_cast` нужно делать от ссылки, например,
`reinterpret_cast<double&>(y)`.
```C++
long long y;
double &d = reinterpret_cast<double&>(y); // UB
d = 3.14;
std::cout << y << std::endl; // какая-то дичь
```
2. По умолчанию это делать нельзя, поэтому в примере выше это UB.
Это можно делать, например, если есть две структуры в которых
типы расположены в одном и том же порядке.
3. `reinterpret_cast` также можно применять к указателям,
но только к совместимым
4. `reinterpret_cast` не позволяет обходить `const`.
Для обхода есть `const_cast`. Он позволяет снять константность.
```C++
const int c = 5;
int &cc = const_cast<int&>(c); // также нужно давать ссылку
cc = 7; // UB
// и также const_cast от ссылки и указателя это две разные сущности
std::cout << c << ' ' << cc << std::endl;
```
Попытка изменить переменную, которая изначально была константой это UB.
C-style cast. Всегда бан в программах на C++. По сути он последовательно перебирает все возможные касты, пока он не подойдет. Например,
вы можете не заметить, как случайно сделаете `const_cast` и словите UB.
Байка от Страуструпа: названия кастов специально сделаны слишком большими, чтобы их меньше хотелось писать.
Ещё есть `dynamic_cast`, но мы пока про него не говорим.
**Стадии сборки**
1. Препроцессинг
2. Компиляция
3. Ассемблирование
4. Линковка
Препроцессор обрабатывает команды препроцессора по типу `#include, #define, ...`. Это не компиляция, а просто обработка текста.
Например, `#include "file"` будет искать файл, `file` в директории файла и в специально указанных путях. Потом он просто заменит эту
строчку содержимым файла. `#include <header>` говорит, что `header` нужно искать __в системе__.
**Упражнение**. Понять, где у вас лежит `iostream`.
Далее компилятор переделывает код(уже без директив с решеткой) в ассемблерный код(`.s`). Далее с помощью ассемблера он уже преобразуется
в объектный файл(уже с машинными инструкциями, `.o`). Далее линкер
преобразует его в исполняемый файл.
В чём разница между `1.cpp -> 1.o` и `a.out`. Линковщик говорит, где нужно искать функции(символы)
# 3 Basics of OOP
## 3.1 Classes and structures, encapsulation
Типы -- классы, данные -- поля классов, операции -- методы классов,
объекты -- экземпляры классов.
Класс можно объявить с помощью ключевого слова `class`, структуру
с помощью ключевого слова `struct`.
Пока мы будем использовать ключевое слово `struct`.
```C++
struct S {
int x; // поле структуры
};
int main() {
S s;
s.x; // обращение к полю x структуры s
std::cout << s.x << std::endl; // UB, так как не инициализировано
}
```
```C++
struct S {
int x = 1;
double d = 3.14;
};
int main() {
S s;
std::cout << s.x << std::endl; // ok, x = 1
}
```
Размер структуры равен сумме полей с точностью до _выравнивания_.
Например `sizeof(S) == 16`, несмотря на то, что `sizeof(int) + sizeof(double) = 12`. Её байты заполнены так: `IIII....DDDDDDDD`, это
сделано в силу того, что восьмибайтные переменные кладутся по адресам кратным 8. Сам объект `S` тоже хочется положить по адресу кратному
8, чтобы их можно было класть подряд. Если бы `S` выглядела так: `IIIIDDDDDDDD`, то две такие нельзя было бы поставить подряд.
Например, можно сделать `reinterpret_cast<int&>(s)`, тогда мы прочитаем `int` с первых четырех байт `S`.
Структуры можно инициализировать агрегатно, `S s{2, 2.718}`.
Внутри структур нельзя писать выражения и объявлять пространства имен. Но можно создавать методы и использовать `using`.
```C++
struct S {
...
void f(int y) {
std::cout << x + y << std::endl;
}
}
int main() {
S s;
s.f(228);
}
```
Внутри структур можно использовать методы до того, как они объявлены в коде.
Можно объявлять методы вне структуры
```C++
void S::f(int y) {
std::cout << x + y;
ff();
}
```
Ключевое слово `this` -- возвращает указатель на объект, в котором мы сейчас находимся.
```C++
struct S {
int x;
double d;
void ff(int x) {
// x and this->x are not the same
}
}
```
Можно объявлять структуры внутри структур(inner class).
Можно анонимно объявлять структуры
```C++
struct {
char c;
} a;
```
Можно объявить структуру прямо внутри функции(local class).
## 3.2 Access modifiers
Одним из основных отличий классаот структуры является возможность
объявить приватное поле/метод. Все поля в структурах по умолчанию публичные, а в классах наоборот приватные, к ним нельзя обратиться
извне.
Ясно, что ошибки доступа проверяются на этапе компиляции.
Модификаторы доступа можно поменять в классе ключевыми словами `public, private`
```C++
class C {
public:
int x;
private:
int y;
public:
int z;
private:
int t;
}
```