struct, class и доступ
Прямоугольник задают два числа — ширина и высота. В отдельных переменных их можно спутать с размерами другого прямоугольника, а функции площади приходится передавать оба числа. Ключевое слово 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 — класс (class): тип, который хранит данные вместе с функциями для работы с ними. Переменные внутри класса называют полями (data members), а функции — методами (member functions). Описание класса само объектов не создаёт: переменная r — объект типа Rect, и у каждого объекта свои поля. Начальное значение полю задают через = или фигурные скобки, как int width = 0;; круглые скобки здесь не работают.
К полям и методам объекта обращаются через точку: r.width, r.area(). Метод всегда вызывают для конкретного объекта, и внутри метода имена полей означают поля этого объекта. В вызове r.area() имя width — это r.width.
Поля с одинаковым доступом лежат в объекте в порядке объявления (declaration). Но sizeof(Rect) может оказаться больше суммы размеров полей. Компилятор (compiler) вправе добавить пустые байты между полями и в конце объекта, чтобы каждое поле получило удобный для процессора адрес.
public и private
Метки public: и private: задают, кому доступны поля и методы. Всё, что идёт после public:, доступно любому коду, а всё, что после private:, — только методам самого класса. Закрытое поле нельзя испортить снаружи: его меняют только методы, а они следят, чтобы значение оставалось верным.
class Counter {
public:
void add() {
++count_;
}
int value() {
return count_;
}
private:
int count_ = 0;
};Для объекта 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. Если полям нужно остаться закрытыми, добавьте открытые методы, которые их меняют.