struct, class и доступ
Чему вы научитесь:
- собирать данные и функции для работы с ними в один класс;
- закрывать поля от чужого кода и задавать их конструктором;
- вызывать через ссылку на базовый класс версию метода настоящего объекта;
- замечать, когда копия производного объекта теряет свою часть.

Представьте механический счётчик-кликер, каким считают посетителей на входе. Внутри у него колёсики с цифрами: это его данные. Снаружи есть две вещи:
- кнопка, которая прибавляет единицу;
- окошко, в котором видно число.
Покрутить колёсики пальцем нельзя: корпус закрыт, и число меняет только кнопка. Поэтому кликер не покажет число, которого никто не набирал.
В C++ такое устройство описывают классом. Данные и действия с ними собраны в один тип, и класс сам решает, что доступно снаружи. Корпуса из пластика у класса нет: закрытость проверяет компилятор, когда собирает программу.
Начнём со сборки данных в одно целое. Прямоугольник задают два числа — ширина и высота. В отдельных переменных их можно спутать с размерами другого прямоугольника, а функции площади приходится передавать оба числа. Ключевое слово struct собирает такие данные в один новый тип:
#include <iostream>
struct Rect {
int width = 0;
int height = 0;
int area() { return width * height; }
};
int main() {
Rect r;
r.width = 3;
r.height = 4;
std::cout << r.area() << '\n'; // 12
}Поля и методы
Rect — класс: тип, который хранит данные вместе с функциями для работы с ними. Переменные внутри класса называют полями, а функции — методами.
Описание класса само объектов не создаёт, как чертёж кликера ещё не кликер. Переменная r — объект типа Rect, и у каждого объекта свои поля. Начальное значение полю задают через = или фигурные скобки, как в int width = 0;. Круглые скобки здесь не работают.
К полям и методам объекта обращаются через точку: r.width, r.area(). Метод всегда вызывают для конкретного объекта, и внутри метода имена полей означают поля этого объекта. В вызове r.area() имя width — это r.width.
Поля с одинаковым доступом лежат в объекте в порядке объявления. Но sizeof(Rect) может оказаться больше суммы размеров полей. Компилятор вправе добавить пустые байты между полями и в конце объекта, чтобы каждое поле получило удобный для процессора адрес.
public и private
Метки public: и private: задают, кому доступны поля и методы. Всё, что идёт после public:, доступно любому коду, а всё, что идёт после private:, доступно только методам самого класса. Закрытое поле нельзя испортить снаружи: его меняют только методы, а они следят, чтобы значение оставалось верным.
class Counter {
public:
void add() {
++count_;
}
int value() {
return count_;
}
private:
int count_ = 0;
};Counter устроен как кликер: add() — кнопка, value() — окошко, а закрытое поле count_ — колёсики внутри корпуса. Для объекта Counter c; код снаружи может вызвать c.add() и c.value(), но строка c.count_ = 100; не скомпилируется. Подчёркивание в конце имени — распространённое соглашение для закрытых полей.
struct и class различаются только доступом по умолчанию: у struct поля и методы без метки открыты, а у class — закрыты. Поэтому struct обычно пишут для наборов открытых данных, а class — когда у типа есть закрытые поля.
Частая ошибка
Тип объявили через class и забыли метку public::
class Rect {
int width = 0;
int height = 0;
};
int main() {
Rect r;
r.width = 3; // ✗
}error: 'width' is a private member of 'Rect'В class поля без метки закрыты, поэтому из main поле width недоступно. Если тип — набор открытых данных, объявите его через struct. Если полям нужно остаться закрытыми, добавьте открытые методы, которые их меняют.
Главное
- Класс собирает поля и методы в один тип, а у каждого объекта свои поля.
- Метод вызывают для объекта через точку, и имена полей внутри метода означают поля этого объекта.
- Поле после
private:доступно только методам самого класса. structиclassразличаются только доступом по умолчанию: уstructвсё открыто, уclassзакрыто.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.