197 lines
7.6 KiB
Markdown
197 lines
7.6 KiB
Markdown
## 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;
|
||
}
|
||
```
|