Шпаргалка по C++
// Комментарий до конца строки /* Многострочный комментарий */ #include <stdio.h> // Вставить содержимое заголовка, поиск по стандартным путям заголовков #include "myfile.h" // Вставить содержимое заголовка, поиск начиная с текущего каталога #define X some text // Замена X на some text #define F(a, b) a + b // Замена F(1, 2) на 1 + 2 #define X \ some text // Многострочное определение макроса #undef X // Удаляет определение макроса #if defined(X) // Условная компиляция (#ifdef X) #else // Опциональная ветвь else (эквивалент #ifndef X или #if !defined(X)) #endif // Завершает блоки #if, #ifdef
Литералы и переменные
255, 0377, 0xff, 0b1011 // Целые числа (десятичные, восьмиричные, шестнадцатиричные, двоичные) 2147483647L, 0x7fffffffl // Целые числа long (64bit на 64-битных UNIX платформах, 32bit на остальных) 123.0, 1.23e2 // Действительные числа двойной точности (double) 'a', '\141', '\x61' // Символы (литеральный, восьмиричный код, шестнадцатиричный код) '\n', '\\', '\'', '\"' // Литералы символа переноса строки, обратного слеша, одинарной кавычки, двойной кавычки "string\n" // Массив символов, завершённый переносом строки и нулевым символом \0 "hello" "world" // Конкатенация двух литералов true, false // Булевы константы ИСТИНА и ЛОЖЬ nullptr // Литерал указателя, указывает на нулевой (недопустимый) адрес
Объявления
int x; // Объявление переменной x типа int, т.е. целого числа (значение не определено) int x = 255; // Объявление переменной и инициализация значением 255 unsigned ing x = 255u; // Объявление переменной типа беззнаковое целое число, инициализация значением 255. char c = 'a'; // Объявление переменной, хранящей символ (однобайтовый, знаковый или беззнаковый) unsigned char u = 255; // Объявление переменной типа "беззнаковый символ" signed char s = -1; // Объявление переменной типа "знаковый символ" float f; // Знаковое действительное число одинарной точности (обычно 4 байта) double f; // Знаковое действительное число двойной точности (обычно 8 байт) bool b = true; // Булевы переменные инициализируются значением true либо false int a[10]; // Массив из 10 целых числе (индексация начиная с нуля, от a[0] до a[9]) int a[] = { 0, 1, 2 }; // Инициализированный массив (эвивалентно a[3] = { 0, 1, 2 };) int a[2][2] = { { 1, 2 }, // Двумерный массив, т.е. массив массивов целых чисел { 4, 5 } }; char str[] = "hello"; // Строка в стиле языка C (6 элементов, включая '\0' в конце) std::string str = "Hello" // Строка в стиле C++, инициализированная значением "Hello" std::string str = R"(Hello World)"; // Строка в стиле C++, инициализированная значением "Hello\nWorld" int* ptr = nullptr; // ptr - указатель на адрес в памяти, предназначенный для хранения int const char* str = "hello"; // str указывает на анонимный массив, хранящий значение "hello\0" void* ptr = nullptr; // ptr хранит адрес нетипизированной области памяти int& ref = x; // ref - ссылка на int x (по сути синоним x) enum Weekend // Weekend - это тип, способный хранить WK_SATURDAY или WK_SUNDAY { WK_SATURDAY, WK_SUNDAY, }; Weekend day; // day - переменная типа weekend enum Weekend // На уровне ассембера тип Weekend представлен целым числом, { // Здесь для WK_SATURDAY и WK_SUNDAY явно назначаем значения 0 и 1 WK_SATURDAY = 0, WK_SUNDAY = 1, }; enum class Color // Современный enum: константы не попадают в глобальную область видимости, { // обращаться к ним можно конструкциями Color::Red и Color::Blue. Red, Blue, }; Color color = Color::Red; // Объявляем переменную типа color, инициализируем значением Color::Red. typedef char* ZeroedString; // Устаревшее добавление синонима типа: объявить `ZeroedString x;` значит объявить `char* x;`. using ZeroedString = char*; // Современное добавление синонима типа. const int c = 3; // Константные значения инициализируются один раз и не могут быть повторно присвоены. const int pow = GetPower(); // Инициализация константы может быть динамической. const int* ptr = arr; // Нельзя записывать значения в память, на которую указывает ptr (т.е. в элементы arr). int* const ptr = arr; // Нельзя менять значение указателя ptr (но можно записывать в память, куда он указывает) const int* const ptr = arr; // Как ptr, так и память, на которую он указывает, недоступны для записи. const int& cref = x; // cref не получится использовать для изменения x int8_t, uint8_t, int16_t, // Целые числа с фиксированным числом бит, не зависящим от платформы. uint16_t, int32_t, uint32_t, int64_t, uint64_t auto it = m.begin(); // Объявляем переменную it, тип выставляется автоматически как тип инициализатора m.begin() auto const param // Объявляем переменную param, тип выставляется автоматически, но будет константным. = config["param"]; auto& instance // Объявляем переменную instance, тип выставляется автоматически, но будет ссылочным = singleton::instance();
Классы памяти
int x; // Память для x выделяется автоматически (обычно на стеке) и существует только в области видимости. static int x; // Память для x выделяется в глобальной области (даже если x объявлена внутри функции). extern int x; // Переменная x объявлена, но её расположение в памяти будет указано в другом месте.
Инструкции
x = y; // Любое невложенное выражение (включая вызов функции, присваивание) является инструкцией. int x = 0; // Объявления являются инструкциями. ; // Пустая инструкция. { // Блок внутри {} является одной инструкцией int x; // Области видимости x - от объявления до конца блока. } if (x) a; // Если значение x - ИСТИНА (не 0), то выполнить инструкцию print('a'); else if (y) print('b'); // Если не x и y, выполняем print('b'), else if необязателен, его можно повторять; else print('c'); // Если не x и не y, выполняем print('c') else необязателен. while (x) // Повторяем 0 или более раз, пока выражение x имеет значение ИСТИНА print(x); for (int i = 0; i < 10; ++i)// Эквивалентно `int i = 0; while (i < 10) { doSomething(); ++i; }` doSomething(); int arr[] = { 5, 10, 20 }; for (auto x : arr) // Range-based цикл for, x последовательно принимает все значения элементов arr. print(x); do // Эквивалентно цепочке `foo(); while(x) foo()`; { foo(); } while (x); switch (x) // Switch выполнит прыжок на один из case/default { // x должен быть целочисленным типом (enum допускается, строки - нет) case X1: a; // Если x == X1 (X1 должно быть константой времени компиляции), продолжаем выполнение отсюда case X2: b; // Иначе если x == X2, продолжаем выполнение отсюда default: c; // В противном случае продолжаем выполнение отсюда (метка default опциональная) } switch (x) { case X1: a; break; // break прерывает выполнение после метки до конца switch, default: // если break нет, то после a будет продолжено выполнени и выполнено c, в отличии от инструкции if c; } break; // Выход из ветвления switch либо из цикла while, do, или for continue; // Прыжок в конец цикла while, do или for return x; // Завершает выполнение функции, возвращает значение x try { a; } catch (const ExceptionType &ex) { b; // Если a; бросает исключение типа ExceptionType, выполнение продолжается здесь } catch (...) { c; // Если a; бросает какое-либо другое исключение, выполнение продолжается здесь }
Функции
int sum(int a, int b); // Объявление функции sum, принимающей два параметра int и возвращающей int void fn(); // fn - это процедура без параметров (псевдо-тип void означает, что возвращаемого значения нет) void fn(int a = 12); // можно написать fn(), и это будет эквивалентно f(12), т.е. параметр имеет значение по умолчанию int sum(int a, int b) // Определение функции sum: тело функции станет её реализацией. { statements; } T operator+(T x, T y) // В выражении вида "a + b", где a, b имеют тип T, вызывается тело функции operator+(a, b) { // Реализация оператора... } T operator-(T x); // Унарный оператор "минус", вызывается в выражениях вида "-a" T operator++(); // Префиксная форма оператора a++ или a-- T operator++(int); // Постфиксная форма оператора a++ или a-- (параметр типа int игнорируется) extern "C" // Все функции, объявленные внутри блока extern "C", не будут подвержены name mangling. { // Это полезно, если функции могут быть вызваны из другого языка (например, из C). void fn(); }
Типы параметров и возвращаемого значения функции могут быть любыми. Функция должна быть либо объявлена (без тела), либо определена (с телом функции) до первого вызова. Можно сначала объявить функцию (и вызвать где-либо), а затем определить (возможно, в другом файле). Каждая программа состоит набора файлов, каждый файл содержит набор глобальных переменных и набор функций. Одна из функций - main - служит точной входа в программу.
int main() { statements... } int main(int argc, char* argv[]) { statements... }
- argv является массивом длины argc, хранящим строки параметров командной строки
- по общему соглашению, main возвращает 0 при успешном выполнении программы, ненулевой код после возникновения ошибки
Функции с различными параметрами могут иметь одинаковое имя (это называется перегрузка функций).
Могут быть перегружены все операторы, кроме “::”, “.”, “.*”, “?:”. Перегрузка не меняет приоритет оператора.
Выражения
Операторы сгруппированы по приоритету, сперва наивысший приоритет. Унарные операторы и присваивание вычисляются справа налево, все остальные слева направо. Во время выполнения программы не происходит проверок на выход за границы массива, на недопустимые указатели и т.п.
T::X // Доступ к символу X, объявленному в классе T N::X // Доступ к символу X, объявленному в пространстве имён N ::X // Доступ к глобальному имени X (может помочь избежать конфликтов имён) t.x // Поле или метод объекта t (структуры или класса) ptr->x // Поле или метод того объекта (структуры или класса), на который указывает ptr arr[i] // i-й элемент массива arr fn(x, y) // Вызов функции fn с аргументами x и y T(x, y) // Конструирование объекта класса T, в конструктор передаются значения x и y x++ // Увеличивает x на единицу, но возвращает старое значение (постфиксная форма) x-- // Вычитает единицу из x, но возвращает старое значение (постфиксная форма) typeid(x) // Вычисляет значение типа std::type_info для объекта x typeid(T) // Вычисляет (обычно при компиляции) значение типа std::type_info для типа T dynamic_cast<T>(x) // Приводит x к типу T во время выполнения, выполняет проверку с помощью // информации о виртуальных методах объекта. static_cast<T>(x) // Приводит x к типу T без каких-либо проверок reinterpret_cast<T>(x) // Интерпретирует байты объекта x как байты объекта типа T const_cast<T>(x) // Конвертирует x к типу T, убирая модификаторы const и volatile sizeof x // Вычисляет число байт, используемое для хранения объекта x sizeof(T) // Вычисляет число байт, используемое для хранения типа T ++x // Увеличивает x на единицу, возвращает новое значение (префиксная форма) --x // Вычитает единицу из x, возвращает новое значение (префиксная форма) ~x // Битовая операция: вычисляет битовое дополнение x !x // Возвращает true если x имеет значение ЛОЖЬ или 0, иначе false -x // Унарный минус +x // Унарный плюс &x // Вычисление адреса x *ptr // Доступ к памяти, на которую указывает ptr (т.е. разыменование, *&x эквивалентно x) new T // Выделяет память для объекта типа T, возвращает его адрес new T(x, y) // Выделяет память для объекта типа T, в конструктор передаёт x, y, возвращает адрес new T[n] // Выделяет память для массива из n элементов типа T delete ptr // Удаляет объект, на который указывает ptr, возвращает системе занятую им память delete[] ptr // Удаляет массив объектов, на которые указывает ptr (T) x // Преобразует x к типу T (устаревшая форма, используйте static_cast или в крайнем случае reinterpret_case) x * y // Умножение x / y // Деление (для целых чисел происходит отбрасывание дробной части) x % y // Получение остатка (знак результата совпадает со знаком x) x + y // Сложение целых чисел либо целочисленного смещения и указателя // (для указателей эквивалентно выражению &x[y]) x - y // Вычитание целых чисел либо получение смещения от указателя y к указателю x x << y // Битовая операция: смещение x на y бит влево, эквивалентно x * pow(2, y) x >> y // Битовая операция: смещение x на y бит вправо, эквивалентно x / pow(2, y) x < y // ИСТИНА, если x меньше чем y x <= y // ИСТИНА, если x меньше или равен y x > y // ИСТИНА, если x больше чем y x >= y // ИСТИНА, если x больше или равен y x & y // Битовая операция "И": 3 & 6 равно 2 x ^ y // Битовая операция "ИСКЛЮЧАЮЩЕЕ ИЛИ": 3 ^ 6 равно 5 x | y // Битовая операция "ИЛИ": 3 | 6 равно 7 x && y // Логическое "И": вычисляет x, и если x ЛОЖЬ, возвращает ЛОЖЬ, иначе // вычисляет y и возвращает его булево значение (ИСТИНА или ЛОЖЬ). x || y // Логическое "ИЛИ": вычисляет x, и если x ИСТИНА, возвращает ИСТИНА, // иначе вычисляет y и возвращает его булево значение (ИСТИНА или ЛОЖЬ). x = y // Присваивает значение y переменной x, возвращает новое значение x x += y // Эквивалент x = x + y, также существуют -= *= /= <<= >>= &= |= ^= x ? y : z // Тернарный оператор: возвращает y если x ИСТИНА, иначе z throw x // Выбрасывает исключение, а если оно не поймано, аварийно завершает программу x, y // Вычисляет x и y, затем возвращает y (редко используется)
Анонимные функции
Анонимные функции поддерживают замыкание, т.е. захват и удержание внешних переменных.
auto fn1 = [] { // Простая анонимная функция типа `void()` /* тело функции */; }; auto fn2 = [] { }; static_assert(!std::is_same_v(fn1, fn2), "Две одинаковые с виду лямбды имеют разные типы." "Каждая лямбда принадлежит уникальному типу данных," "имеющему operator()."); int value1 = 10; // Захватим value1 по значению: [value] int value2 = 10; // Захватим value2 по ссылке: [&value2] auto fn = [value1, &value2] { ++value1; ++value2; }; assert(value1 == 10); // Значение не изменилось (изменялась копия) assert(value2 == 11); // Значение изменилось auto sum = [](int a, int b) -> int { return a + b; }; int x = sum(10, 50); // sum принимает 2 параметра int, возвращает int int count = 0; // mutable означает, что захваченное // по значению сохраняется между вызовами auto bump = [count]() mutable { ++count; printf("count: %d", count); }; bump(); // печатает 'count: 1' bump(); // печатает 'count: 2' auto sum = [](auto && a, auto && b) { return a + b; // возвращаемый тип определится автоматически }; double x = sum(10.2, 40); // sum - обобщённая анонимная функция, // псевдо-тип auto служит местом // для параметра любого типа // Условие в if constexpr вычисляется при компиляции, // это позволяет в одной обобщённой анонимной функции // обработать разные типы данных. auto println = [](auto && value) { if constexpr (typeid(value) == typeid(int)) { printf("%d\n", value); } if constexpr (typeid(value) == typeid(std::string)) { printf("%s\n", value.c_str()); } };
Классы
class T // Новый тип данных T { private: // В этой секции символы доступны только для методов класса T protected: // В этой секции символы доступны ещё для классов-наследников класса T public: // В этой секции символы доступны для всех желающих int x; // Поле класса, располагается в памяти как часть объекта класса void f(); // Метод (функция, являющаяся членом класса) void g() { return; } // Метод с телом, встроенным в класс void h() const; // Метод не сможет модифицировать какие-либо поля класса int operator+(int y); // t + y превращается в вызов метода-оператора t.operator+(y) int operator-(); // -t превращается в вызов метода-оператора t.operator-() T(): x(1) {} // Конструктор использует списки инициализации конструктора: ": x(1)" T(const T& t): x(t.x) {}// Конструктор копирования T& operator=(const T& t)// Оператор присваивания { x = t.x; return *this; } ~T(); // Деструктор (автоматически вызываемая процедура очистки) explicit T(int a); // Позволяет писать t = T(3), но не t = 3 T(float x): T((int)x) {}// Делегирующий конструктор, делегирует инициализацию в T(int) operator int() const {return x;} // Оператор преобразования в int, допускает код x = int(t) static int y; // Поле y становится единственным и глобальным для всех объектов типа T static void l(); // Метод становится методом класса, доступен для вызова через T::l() class Z {}; // Вложенный класс T::Z typedef int Int; // T::Int - синоним типа int }; void T::fn() // Тело метода fn класса T { this->x = x; // this - это адрес текущего объекта (здесь поле x копируется в поле x) } int T::y = 2; // Инициализация статической переменной // (должна быть вне класса для всех типов, кроме целочисленных) T::l(); // Вызов статического метода (метода класса) T t; // Создание объекта t типа T с неявным вызовом конструктора T() t.f(); // Вызов метода f объекта t struct T { // Эквивалентно коду class T { public: virtual void i(); // Реализация виртуального метода i может быть перегружена классом-наследником virtual void g() = 0; // Чисто виртуальный метод, должен быть перезаписан в классе-наследнике }; class U : public T // Дочерний класс U наследует все поля и методы базового класса T { public: void g(int) override; // Перегрузка метода g };
Все классы по умолчанию имеют конструктор копирования, оператор присваивания и деструктор, которые рекурсивно вызывают соответствующие методы для базовых классов и полей. Примитивные типы, такие как целые числа, указатели и т.п., копируются прямым копированием памяти, а их деструктор ничего не делает. Конструкторы, операторы присваивания и дееструкторы никогда не копируются. Если у класса не указан ни один конструктор, то у него есть конструктор по умолчанию без аргументов, который лишь вызывает другие конструкторы.
Шаблоны
template <class T> // Функция fn будет перегружена для любых типов-аргументов T fn(T t); template <class T> class X // Класс параметризуется типом T { X(T t); // Конструктор принимает значение типа T }; template <class T> X<T>::X(T t) // Определение конструктора (метода) за пределами класса { } X<int> x(3); // Тип объекта x - это X<int>, специализация шаблонного класса X template <class T, class U = T, int n = 0> class A // Шаблон имеет типы-параметры с типами по умолчанию { };
Пространства имён
namespace N {class T {};} // Помещает имя T в пространство имён N N::T t; // Используем имя T из пространства имён N using namespace N; // Все символы из пространства имён N теперь доступны без префикса N:: using N::T; // Символ N::T теперь доступен без префикса N::
Отладочный механизм assert
#include <cassert> // Включаем cassert assert(cond); // Если условие cond не выполняется, распечатать сообщение и аварийно // завершить программу. В Release-конфигурациях объявлен макрос // NDEBUG, который превращает assert в пустой макрос. Пустой макрос // ничего не выполняет и не вычисляет выражение cond.