LEARN X · ЗА 20 МИН
C++
Экспресс-тур по C++ за 20 минут: типы, циклы, строки, векторы, STL, классы, шаблоны, указатели и умные указатели — весь язык на одной странице.
C++ — компилируемый язык с ручным управлением памятью, классами, шаблонами и богатой стандартной библиотекой (STL). За 20 минут пробежимся по всему языку: от вывода в консоль до умных указателей. Весь материал — в комментариях к коду, читайте сверху вниз. Примеры рассчитаны на стандарт C++17.
Структура программы и вывод
Любая программа на C++ начинается с функции main.
#include <iostream> // подключаем библиотеку ввода-вывода
// Однострочный комментарий
/* Многострочный
комментарий */
int main() { // точка входа, возвращает код завершения
std::cout << "Привет, мир!" << std::endl; // вывод + перевод строки
std::cout << "Без endl\n"; // \n тоже перевод строки
return 0; // 0 = успешное завершение
}
// Вывод:
// Привет, мир!
// Без endl
Переменные и типы
int n = 42; // целое
double pi = 3.14; // вещественное (double точнее float)
float f = 1.5f; // одинарная точность
char c = 'A'; // один символ (в одинарных кавычках)
bool flag = true; // логический: true / false
auto x = 10; // тип выведет компилятор -> int
auto y = 2.5; // -> double
const int MAX = 100; // константа, менять нельзя
unsigned int u = 7; // только неотрицательные
long long big = 9000000000LL; // большое целое
std::cout << n << " " << pi << " " << c << "\n"; // 42 3.14 A
std::cout << sizeof(int) << "\n"; // размер типа в байтах, обычно 4
Ввод-вывод
std::cin читает данные, std::getline — целую строку.
#include <iostream>
#include <string>
int main() {
int age;
std::cout << "Возраст: ";
std::cin >> age; // читаем число до пробела/перевода строки
std::cin.ignore(); // убираем '\n' из буфера после >>
std::string name;
std::cout << "Имя: ";
std::getline(std::cin, name); // читаем всю строку, включая пробелы
std::cout << name << ", " << age << " лет\n";
return 0;
}
Операторы и условия
int a = 5, b = 3;
// Арифметика: + - * / % (целочисленное деление отбрасывает дробь)
std::cout << a / b << " " << a % b << "\n"; // 1 2
// Сравнение: == != < > <= >=
// Логика: && || !
if (a > b) {
std::cout << "a больше\n";
} else if (a == b) {
std::cout << "равны\n";
} else {
std::cout << "b больше\n";
}
// Тернарный оператор
int max = (a > b) ? a : b; // max = 5
// switch — выбор по значению
int day = 3;
switch (day) {
case 1: std::cout << "Пн\n"; break; // break обязателен
case 3: std::cout << "Ср\n"; break;
default: std::cout << "?\n";
}
Циклы
// for: инициализация; условие; шаг
for (int i = 0; i < 3; i++) {
std::cout << i << " "; // 0 1 2
}
std::cout << "\n";
// range-based for: перебор элементов коллекции
int nums[] = {10, 20, 30};
for (int x : nums) {
std::cout << x << " "; // 10 20 30
}
std::cout << "\n";
// while: пока условие истинно
int k = 0;
while (k < 3) { std::cout << k; k++; } // 012
std::cout << "\n";
// do-while: тело выполнится хотя бы раз
int m = 5;
do { std::cout << m; m++; } while (m < 3); // 5
// break прерывает цикл, continue пропускает итерацию
Строки
std::string — удобная строка из заголовка <string>.
#include <string>
std::string s = "Привет";
s += ", мир"; // конкатенация
std::cout << s.length() << "\n"; // длина в байтах (UTF-8!)
std::cout << s.size() << "\n"; // то же самое
std::string a = "abc";
std::cout << a[0] << "\n"; // 'a' — доступ по индексу
std::cout << a.substr(1, 2) << "\n"; // "bc" (с позиции 1, длина 2)
std::cout << a.find("b") << "\n"; // 1 (индекс) или string::npos
std::cout << (a == "abc") << "\n"; // 1 (сравнение строк работает)
a.append("!"); // a = "abc!"
std::cout << a.empty() << "\n"; // 0 (не пустая)
// Число <-> строка
int n = std::stoi("123"); // строка -> int
std::string t = std::to_string(45); // int -> строка
Массивы и векторы
std::vector — динамический массив, который растёт сам.
#include <vector>
int arr[3] = {1, 2, 3}; // статический массив фиксированной длины
std::cout << arr[0] << "\n"; // 1
std::vector<int> v = {10, 20}; // вектор
v.push_back(30); // добавить в конец -> {10,20,30}
v.pop_back(); // удалить последний -> {10,20}
std::cout << v.size() << "\n"; // 2
std::cout << v[0] << "\n"; // 10
std::cout << v.front() << " " << v.back() << "\n"; // 10 20
v.insert(v.begin(), 5); // вставить в начало -> {5,10,20}
v.clear(); // очистить
std::cout << v.empty() << "\n"; // 1
std::vector<int> w(5, 0); // 5 элементов, все = 0
for (int x : w) std::cout << x; // 00000
Контейнеры STL
map — ключ-значение, set — уникальные значения, pair — пара.
#include <map>
#include <set>
#include <utility>
std::map<std::string, int> ages; // словарь (ключи отсортированы)
ages["Аня"] = 25;
ages["Боб"] = 30;
std::cout << ages["Аня"] << "\n"; // 25
std::cout << ages.count("Боб") << "\n"; // 1 (есть ли ключ)
for (auto& [name, age] : ages) // перебор пар (C++17)
std::cout << name << "=" << age << " "; // Аня=25 Боб=30
std::cout << "\n";
std::set<int> uniq = {3, 1, 2, 2}; // дубликаты отбрасываются
uniq.insert(5); // {1,2,3,5}
std::cout << uniq.count(2) << "\n"; // 1
std::pair<int, std::string> p = {1, "раз"};
std::cout << p.first << " " << p.second << "\n"; // 1 раз
Функции
// Объявление: тип_возврата имя(параметры)
int square(int x) {
return x * x;
}
// Параметр по умолчанию
int power(int base, int exp = 2) {
int r = 1;
for (int i = 0; i < exp; i++) r *= base;
return r;
}
// Передача по ссылке (&) — функция меняет оригинал
void increment(int& n) {
n++;
}
// Перегрузка: одно имя, разные параметры
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
int main() {
std::cout << square(5) << "\n"; // 25
std::cout << power(3) << "\n"; // 9 (exp по умолчанию = 2)
std::cout << power(2, 3) << "\n"; // 8
int v = 10;
increment(v);
std::cout << v << "\n"; // 11
std::cout << add(1, 2) << " " << add(1.5, 2.5) << "\n"; // 3 4
}
Указатели и ссылки
Указатель хранит адрес, ссылка — псевдоним переменной.
int x = 42;
int* ptr = &x; // & — адрес переменной
std::cout << *ptr << "\n"; // * — разыменование -> 42
*ptr = 100; // меняем x через указатель
std::cout << x << "\n"; // 100
int& ref = x; // ссылка = другое имя для x
ref = 7; // меняет x
std::cout << x << "\n"; // 7
int* empty = nullptr; // пустой указатель (не 0/NULL)
if (empty == nullptr) std::cout << "пусто\n";
// Динамическая память: new выделяет, delete освобождает
int* num = new int(5); // выделяем int со значением 5
std::cout << *num << "\n"; // 5
delete num; // обязательно освободить!
int* arr = new int[3]{1,2,3}; // массив в куче
delete[] arr; // для массива — delete[]
Классы и ООП
class объединяет данные и методы. Наследование и виртуальные методы дают полиморфизм.
#include <string>
class Animal {
protected: // доступно наследникам
std::string name;
public:
Animal(std::string n) : name(n) { // конструктор
std::cout << "Создан " << name << "\n";
}
virtual ~Animal() {} // виртуальный деструктор
virtual void sound() { // virtual — можно переопределить
std::cout << "...\n";
}
std::string getName() { return name; }
};
class Dog : public Animal { // Dog наследует Animal
public:
Dog(std::string n) : Animal(n) {}
void sound() override { // override — переопределяем
std::cout << name << ": Гав!\n";
}
};
int main() {
Animal* a = new Dog("Рекс"); // Создан Рекс
a->sound(); // Рекс: Гав! (полиморфизм)
delete a;
}
Шаблоны
Шаблоны позволяют писать код, работающий с любым типом T.
// Шаблон функции
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}
// Шаблон класса
template <typename T>
class Box {
T value;
public:
Box(T v) : value(v) {}
T get() { return value; }
};
int main() {
std::cout << maximum(3, 7) << "\n"; // 7 (T = int)
std::cout << maximum(2.5, 1.1) << "\n"; // 2.5 (T = double)
std::cout << maximum('a', 'z') << "\n"; // z
Box<int> bi(42);
Box<std::string> bs("hi");
std::cout << bi.get() << " " << bs.get() << "\n"; // 42 hi
}
Алгоритмы STL
Заголовок <algorithm> + лямбды дают мощные операции над коллекциями.
#include <vector>
#include <algorithm>
std::vector<int> v = {5, 2, 8, 1, 9};
std::sort(v.begin(), v.end()); // {1,2,5,8,9}
std::sort(v.begin(), v.end(),
[](int a, int b){ return a > b; }); // по убыванию: {9,8,5,2,1}
// Лямбда: [захват](параметры){ тело }
auto it = std::find(v.begin(), v.end(), 8);
if (it != v.end()) std::cout << "найдено\n";
int cnt = std::count_if(v.begin(), v.end(),
[](int x){ return x > 4; }); // 3 элемента > 4
std::cout << cnt << "\n"; // 3
int sum = std::accumulate(v.begin(), v.end(), 0); // нужен <numeric>
std::cout << *std::max_element(v.begin(), v.end()) << "\n"; // 9
std::for_each(v.begin(), v.end(), [](int x){ std::cout << x << " "; });
Умные указатели
Умные указатели из <memory> сами освобождают память — delete не нужен.
#include <memory>
// unique_ptr — единственный владелец, нельзя копировать
std::unique_ptr<int> u = std::make_unique<int>(10);
std::cout << *u << "\n"; // 10
// память освободится автоматически в конце области видимости
// shared_ptr — счётчик ссылок, владельцев может быть много
std::shared_ptr<int> s1 = std::make_shared<int>(20);
std::shared_ptr<int> s2 = s1; // оба владеют одним объектом
std::cout << *s2 << "\n"; // 20
std::cout << s1.use_count() << "\n"; // 2 (число владельцев)
// объект удалится, когда счётчик станет 0
// Зачем: исключают утечки памяти и двойной delete