## 2.7 Type conversions `static_cast` -- ключевое слово языка C++ ```C++ T x; static_cast(x); ``` С помощью него неявные преобразования можно сделать явно через `static_cast`, такие как `double -> int, A* -> void*`. `reinterpret_cast` -- говорит компилятору трактовать переменную `x` как переменную типа `U` побитово. То есть интерпретировать память как будто бы там лежит другой тип. 1. `reinterpret_cast` нужно делать от ссылки, например, `reinterpret_cast(y)`. ```C++ long long y; double &d = reinterpret_cast(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(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` нужно искать __в системе__. **Упражнение**. Понять, где у вас лежит `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(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; } ```