C++
Шпаргалка по C++: структура программы, ввод-вывод, типы, строки, векторы, циклы, функции, указатели, ООП, STL, алгоритмы, шаблоны и умные указатели.
C++ — компилируемый язык общего назначения с поддержкой процедурного, объектно-ориентированного и обобщённого программирования. Эта шпаргалка собирает базовый синтаксис современного C++ (стандарт C++11 и новее): от структуры программы до STL, шаблонов и умных указателей. Все примеры рабочие — их можно скомпилировать командой g++ -std=c++17 file.cpp -o app.
Структура программы
Любая программа на C++ начинается с подключения заголовочных файлов через #include и содержит функцию main() — точку входа. Директива using namespace std; позволяет не писать префикс std:: перед именами из стандартной библиотеки.
#include <iostream> // подключаем библиотеку ввода-вывода
using namespace std; // чтобы не писать std:: каждый раз
int main() {
cout << "Привет, мир!" << endl;
return 0; // 0 — программа завершилась успешно
}
// Вывод: Привет, мир!
Без using namespace std; к именам обращаются через std:: — это считается более чистым стилем в больших проектах.
#include <iostream>
int main() {
std::cout << "Без using" << std::endl;
return 0;
}
// Вывод: Без using
Ввод и вывод
Поток cout с оператором << выводит данные, поток cin с оператором >> читает их. Оператор >> читает до пробела, поэтому для строк с пробелами используют getline.
#include <iostream>
#include <string>
using namespace std;
int main() {
int age;
cout << "Возраст: ";
cin >> age; // читаем число
cout << "Вам " << age << " лет" << endl;
return 0;
}
// Ввод: 25
// Вывод: Вам 25 лет
getline читает всю строку целиком, включая пробелы, до символа перевода строки.
#include <iostream>
#include <string>
using namespace std;
int main() {
string name;
cout << "Имя: ";
getline(cin, name); // читаем строку с пробелами
cout << "Привет, " << name << "!" << endl;
return 0;
}
// Ввод: Иван Петров
// Вывод: Привет, Иван Петров!
Переменные и типы
C++ — статически типизированный язык: тип переменной указывается при объявлении. Основные типы: int, double, char, bool. Ключевое слово auto позволяет компилятору вывести тип автоматически, а const объявляет неизменяемое значение.
#include <iostream>
using namespace std;
int main() {
int count = 10; // целое число
double price = 99.9; // число с плавающей точкой
char grade = 'A'; // один символ
bool isReady = true; // логический тип
const double PI = 3.14159; // константа
auto sum = count + 5; // тип выведен: int
cout << count << " " << price << " " << grade << " " << isReady << endl;
cout << "sum = " << sum << ", PI = " << PI << endl;
return 0;
}
// Вывод: 10 99.9 A 1
// sum = 15, PI = 3.14159
Таблица основных типов:
| Тип | Описание | Пример значения |
|---|---|---|
| int | целое число | 42, -7 |
| double | дробное число | 3.14, -0.5 |
| char | один символ | 'A', '9' |
| bool | истина/ложь | true, false |
| std::string | строка | "привет" |
Строки
Тип std::string из заголовка <string> — это удобная обёртка над массивом символов. Строки можно складывать оператором +, измерять методом size() и обращаться к символам по индексу.
#include <iostream>
#include <string>
using namespace std;
int main() {
string a = "Hello";
string b = "World";
string c = a + ", " + b; // конкатенация
cout << c << endl; // Hello, World
cout << "Длина: " << c.size() << endl; // 12
cout << "Первый символ: " << c[0] << endl; // H
return 0;
}
// Вывод: Hello, World
// Длина: 12
// Первый символ: H
Полезные методы строк:
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "программирование";
cout << s.substr(0, 5) << endl; // програ — подстрока
cout << s.find("рам") << endl; // позиция вхождения
cout << (s.empty() ? "пусто" : "есть") << endl;
s.append("!"); // добавить в конец
cout << s << endl;
return 0;
}
// substr возвращает первые 5 символов
// find возвращает индекс подстроки
Массивы и векторы
Классический массив C++ имеет фиксированный размер. В современном C++ предпочитают std::vector — динамический массив, который умеет менять размер во время работы программы.
#include <iostream>
using namespace std;
int main() {
int arr[3] = {10, 20, 30}; // массив фиксированного размера
for (int i = 0; i < 3; i++) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
// Вывод: 10 20 30
std::vector<int> — динамический массив из заголовка <vector>. Элементы добавляют методом push_back, размер узнают через size().
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> nums = {1, 2, 3};
nums.push_back(4); // добавить элемент
nums.push_back(5);
cout << "Размер: " << nums.size() << endl;
for (int x : nums) { // range-based for
cout << x << " ";
}
cout << endl;
return 0;
}
// Вывод: Размер: 5
// 1 2 3 4 5
Операторы
C++ поддерживает арифметические, сравнения и логические операторы. Деление целых чисел отбрасывает дробную часть, а оператор % возвращает остаток.
#include <iostream>
using namespace std;
int main() {
int a = 17, b = 5;
cout << a + b << endl; // 22
cout << a / b << endl; // 3 (целочисленное деление)
cout << a % b << endl; // 2 (остаток)
bool x = (a > b) && (b > 0); // логическое И
bool y = (a < b) || (b > 0); // логическое ИЛИ
cout << x << " " << y << endl; // 1 1
return 0;
}
// Вывод: 22
// 3
// 2
// 1 1
Условия: if и switch
Конструкция if / else if / else выбирает ветку по логическому условию.
#include <iostream>
using namespace std;
int main() {
int score = 75;
if (score >= 90) {
cout << "Отлично" << endl;
} else if (score >= 60) {
cout << "Хорошо" << endl;
} else {
cout << "Нужно повторить" << endl;
}
return 0;
}
// Вывод: Хорошо
Оператор switch удобен для выбора по конкретным значениям. Не забывайте break, иначе выполнение «провалится» в следующий case.
#include <iostream>
using namespace std;
int main() {
int day = 3;
switch (day) {
case 1: cout << "Понедельник"; break;
case 3: cout << "Среда"; break;
default: cout << "Другой день";
}
cout << endl;
return 0;
}
// Вывод: Среда
Циклы
Цикл for с тремя частями (инициализация; условие; шаг) удобен для счётчиков.
#include <iostream>
using namespace std;
int main() {
for (int i = 1; i <= 5; i++) {
cout << i << " ";
}
cout << endl;
return 0;
}
// Вывод: 1 2 3 4 5
Range-based for (C++11) перебирает элементы коллекции без индексов. Ссылка & позволяет менять элементы на месте.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {2, 4, 6};
for (int& x : v) { // ссылка — меняем оригинал
x *= 10;
}
for (int x : v) cout << x << " ";
cout << endl;
return 0;
}
// Вывод: 20 40 60
Цикл while повторяется, пока условие истинно.
#include <iostream>
using namespace std;
int main() {
int n = 8;
while (n > 1) {
cout << n << " ";
n /= 2;
}
cout << endl;
return 0;
}
// Вывод: 8 4 2
Функции
Функция объявляется с типом возвращаемого значения, именем и списком параметров. По умолчанию аргументы передаются по значению — функция работает с копией.
#include <iostream>
using namespace std;
int square(int x) { // передача по значению
return x * x;
}
int main() {
cout << square(6) << endl; // 36
return 0;
}
// Вывод: 36
Передача по ссылке через & позволяет функции изменить оригинальную переменную без копирования.
#include <iostream>
using namespace std;
void doubleIt(int& x) { // ссылка — меняем оригинал
x *= 2;
}
int main() {
int a = 5;
doubleIt(a);
cout << a << endl; // 10
return 0;
}
// Вывод: 10
Перегрузка: несколько функций с одним именем, но разными параметрами. Компилятор выбирает нужную по типам аргументов.
#include <iostream>
using namespace std;
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
int main() {
cout << add(2, 3) << endl; // 5 (int)
cout << add(2.5, 3.1) << endl; // 5.6 (double)
return 0;
}
// Вывод: 5
// 5.6
Указатели и ссылки
Указатель хранит адрес переменной. Оператор & берёт адрес, оператор * разыменовывает указатель (получает значение по адресу). Ссылка — это псевдоним существующей переменной.
#include <iostream>
using namespace std;
int main() {
int value = 42;
int* ptr = &value; // указатель на value
int& ref = value; // ссылка на value
cout << *ptr << endl; // 42 — значение по адресу
*ptr = 100; // меняем через указатель
cout << value << endl; // 100
ref = 7; // меняем через ссылку
cout << value << endl; // 7
return 0;
}
// Вывод: 42
// 100
// 7
Главное отличие: указатель можно перенаправить на другой объект или сделать nullptr, а ссылка привязана к одной переменной навсегда.
ООП: классы и структуры
class объединяет данные и методы. По умолчанию члены класса private (скрыты), а public делает их доступными извне. Конструктор инициализирует объект при создании.
#include <iostream>
#include <string>
using namespace std;
class Person {
private:
string name;
int age;
public:
Person(string n, int a) { // конструктор
name = n;
age = a;
}
void greet() {
cout << "Я " << name << ", мне " << age << endl;
}
};
int main() {
Person p("Анна", 30);
p.greet();
return 0;
}
// Вывод: Я Анна, мне 30
struct работает почти как класс, но по умолчанию все члены public — удобно для простых контейнеров данных.
#include <iostream>
using namespace std;
struct Point {
int x;
int y;
};
int main() {
Point p = {3, 4};
cout << p.x << ", " << p.y << endl;
return 0;
}
// Вывод: 3, 4
Наследование и виртуальные методы: производный класс наследует базовый, а virtual обеспечивает полиморфизм — вызов нужной версии метода по реальному типу объекта.
#include <iostream>
using namespace std;
class Animal {
public:
virtual void sound() { // виртуальный метод
cout << "..." << endl;
}
};
class Dog : public Animal { // наследование
public:
void sound() override {
cout << "Гав!" << endl;
}
};
int main() {
Animal* a = new Dog();
a->sound(); // Гав! — выбран метод Dog
delete a;
return 0;
}
// Вывод: Гав!
STL: контейнеры
Standard Template Library предоставляет готовые контейнеры. std::vector<int> — динамический массив, std::map<K,V> — ассоциативный массив (ключ-значение), std::set<T> — множество уникальных значений.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> ages;
ages["Иван"] = 25; // ключ -> значение
ages["Мария"] = 30;
for (auto& pair : ages) {
cout << pair.first << ": " << pair.second << endl;
}
return 0;
}
// Вывод: Иван: 25
// Мария: 30 (отсортировано по ключу)
std::set<int> хранит только уникальные элементы в отсортированном порядке.
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> nums;
nums.insert(5);
nums.insert(2);
nums.insert(5); // дубликат игнорируется
for (int x : nums) cout << x << " ";
cout << endl;
cout << "Есть 2? " << (nums.count(2) ? "да" : "нет") << endl;
return 0;
}
// Вывод: 2 5
// Есть 2? да
Краткий обзор контейнеров:
| Контейнер | Назначение | Заголовок |
|---|---|---|
| vector | динамический массив | <vector> |
| map | пары ключ-значение (отсортированы) | <map> |
| set | уникальные значения | <set> |
| string | строка символов | <string> |
Алгоритмы STL
Заголовок <algorithm> содержит готовые функции для работы с диапазонами. sort сортирует, find ищет элемент.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> v = {5, 2, 8, 1, 9};
sort(v.begin(), v.end()); // по возрастанию
for (int x : v) cout << x << " ";
cout << endl;
return 0;
}
// Вывод: 1 2 5 8 9
find возвращает итератор; если элемент не найден — это end().
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> v = {10, 20, 30};
auto it = find(v.begin(), v.end(), 20);
if (it != v.end()) {
cout << "Найдено на позиции " << (it - v.begin()) << endl;
} else {
cout << "Не найдено" << endl;
}
return 0;
}
// Вывод: Найдено на позиции 1
Шаблоны (templates)
Шаблоны позволяют писать обобщённый код, работающий с любым типом. Компилятор сам подставляет конкретный тип при вызове.
#include <iostream>
#include <string>
using namespace std;
template <typename T>
T getMax(T a, T b) { // работает с любым типом
return (a > b) ? a : b;
}
int main() {
cout << getMax(3, 7) << endl; // 7
cout << getMax(4.5, 1.2) << endl; // 4.5
cout << getMax(string("abc"), string("xyz")) << endl; // xyz
return 0;
}
// Вывод: 7
// 4.5
// xyz
Именно на шаблонах построена вся STL — vector<int>, vector<string> и map<string,int> это разные подстановки одного шаблона.
Умные указатели
Умные указатели из <memory> автоматически освобождают память — не нужно вручную вызывать delete. unique_ptr владеет объектом единолично, shared_ptr разделяет владение через счётчик ссылок.
#include <iostream>
#include <memory>
using namespace std;
int main() {
unique_ptr<int> p = make_unique<int>(42);
cout << *p << endl; // 42
*p = 100;
cout << *p << endl; // 100
// память освободится автоматически при выходе из main
return 0;
}
// Вывод: 42
// 100
shared_ptr ведёт счётчик: память освобождается, когда последний владелец уничтожен.
#include <iostream>
#include <memory>
using namespace std;
int main() {
shared_ptr<int> a = make_shared<int>(5);
shared_ptr<int> b = a; // оба указывают на одно значение
cout << *a << " " << *b << endl; // 5 5
cout << "Владельцев: " << a.use_count() << endl; // 2
return 0;
}
// Вывод: 5 5
// Владельцев: 2
Совет: в современном C++ предпочитайте умные указатели «голым» new/delete — это избавляет от утечек памяти.