static_cast – ключевое слово языка C++
T x;
static_cast<U>(x);С помощью него неявные преобразования можно сделать явно через
static_cast, такие как
double -> int, A* -> void*.
reinterpret_cast – говорит компилятору трактовать
переменную x как переменную типа U побитово.
То есть интерпретировать память как будто бы там лежит другой тип.
reinterpret_cast нужно делать от ссылки, например,
reinterpret_cast<double&>(y).long long y;
double &d = reinterpret_cast<double&>(y); // UB
d = 3.14;
std::cout << y << std::endl; // какая-то дичьПо умолчанию это делать нельзя, поэтому в примере выше это UB. Это можно делать, например, если есть две структуры в которых типы расположены в одном и том же порядке.
reinterpret_cast также можно применять к указателям,
но только к совместимым
reinterpret_cast не позволяет обходить
const.
Для обхода есть const_cast. Он позволяет снять
константность.
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, но мы пока про него не
говорим.
Стадии сборки
Препроцессинг
Компиляция
Ассемблирование
Линковка
Препроцессор обрабатывает команды препроцессора по типу
#include, #define, .... Это не компиляция, а просто
обработка текста.
Например, #include "file" будет искать файл,
file в директории файла и в специально указанных путях.
Потом он просто заменит эту строчку содержимым файла.
#include <header> говорит, что header
нужно искать в системе.
Упражнение. Понять, где у вас лежит
iostream.
Далее компилятор переделывает код(уже без директив с решеткой) в
ассемблерный код(.s). Далее с помощью ассемблера он уже
преобразуется в объектный файл(уже с машинными инструкциями,
.o). Далее линкер преобразует его в исполняемый файл.
В чём разница между 1.cpp -> 1.o и
a.out. Линковщик говорит, где нужно искать
функции(символы)
Типы – классы, данные – поля классов, операции – методы классов, объекты – экземпляры классов.
Класс можно объявить с помощью ключевого слова class,
структуру с помощью ключевого слова struct.
Пока мы будем использовать ключевое слово struct.
struct S {
int x; // поле структуры
};
int main() {
S s;
s.x; // обращение к полю x структуры s
std::cout << s.x << std::endl; // UB, так как не инициализировано
}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.
struct S {
...
void f(int y) {
std::cout << x + y << std::endl;
}
}
int main() {
S s;
s.f(228);
}Внутри структур можно использовать методы до того, как они объявлены в коде.
Можно объявлять методы вне структуры
void S::f(int y) {
std::cout << x + y;
ff();
}Ключевое слово this – возвращает указатель на объект, в
котором мы сейчас находимся.
struct S {
int x;
double d;
void ff(int x) {
// x and this->x are not the same
}
}Можно объявлять структуры внутри структур(inner class).
Можно анонимно объявлять структуры
struct {
char c;
} a;Можно объявить структуру прямо внутри функции(local class).
Одним из основных отличий классаот структуры является возможность объявить приватное поле/метод. Все поля в структурах по умолчанию публичные, а в классах наоборот приватные, к ним нельзя обратиться извне.
Ясно, что ошибки доступа проверяются на этапе компиляции.
Модификаторы доступа можно поменять в классе ключевыми словами
public, private
class C {
public:
int x;
private:
int y;
public:
int z;
private:
int t;
}