pandoc-pages/pages/mipt_cxx1/06.md
2023-10-09 20:00:51 +03:00

197 lines
7.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 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;
}
```