Перейти к содержимому
Теория · Классы и ООП · урок 1 из 15

struct, class и доступ

Чему вы научитесь

Чему вы научитесь:

  • собирать данные и функции для работы с ними в один класс;
  • закрывать поля от чужого кода и задавать их конструктором;
  • вызывать через ссылку на базовый класс версию метода настоящего объекта;
  • замечать, когда копия производного объекта теряет свою часть.
Механический счётчик-кликер в разрезе: кнопка add(), окошко value() и колёсики count_ под замком внутри корпуса

Представьте механический счётчик-кликер, каким считают посетителей на входе. Внутри у него колёсики с цифрами: это его данные. Снаружи есть две вещи:

  • кнопка, которая прибавляет единицу;
  • окошко, в котором видно число.

Покрутить колёсики пальцем нельзя: корпус закрыт, и число меняет только кнопка. Поэтому кликер не покажет число, которого никто не набирал.

В C++ такое устройство описывают классом. Данные и действия с ними собраны в один тип, и класс сам решает, что доступно снаружи. Корпуса из пластика у класса нет: закрытость проверяет компилятор, когда собирает программу.

Начнём со сборки данных в одно целое. Прямоугольник задают два числа — ширина и высота. В отдельных переменных их можно спутать с размерами другого прямоугольника, а функции площади приходится передавать оба числа. Ключевое слово struct собирает такие данные в один новый тип:

C++
#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:, доступно только методам самого класса. Закрытое поле нельзя испортить снаружи: его меняют только методы, а они следят, чтобы значение оставалось верным.

C++
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::

C++
class Rect {
    int width = 0;
    int height = 0;
};

int main() {
    Rect r;
    r.width = 3;  // ✗
}
TEXT
error: 'width' is a private member of 'Rect'

В class поля без метки закрыты, поэтому из main поле width недоступно. Если тип — набор открытых данных, объявите его через struct. Если полям нужно остаться закрытыми, добавьте открытые методы, которые их меняют.

Главное

  • Класс собирает поля и методы в один тип, а у каждого объекта свои поля.
  • Метод вызывают для объекта через точку, и имена полей внутри метода означают поля этого объекта.
  • Поле после private: доступно только методам самого класса.
  • struct и class различаются только доступом по умолчанию: у struct всё открыто, у class закрыто.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом