Перейти к содержанию
Educora
Средний20 мин7 / 10

Классы и объекты

Создавай собственные типы: члены класса, методы, конструкторы и деструкторы, инкапсуляция с помощью `public` и `private`.

Проверь себя
В этом уроке ты узнаешь
  • Объяснять понятия класса и объекта
  • Писать класс с полями и методами
  • Писать конструкторы со списком инициализации и деструктор
  • Защищать данные с помощью public и private

В игре сотни персонажей: у каждого есть имя, здоровье и уровень, и каждый умеет двигаться и атаковать. Хранить всё это в отдельных переменных и функциях — быстро запутаешься. C++ позволяет создать собственный тип — класс. Класс объединяет данные и функции, которые с ними работают.

Класс и объект

Определение
Класс и объект

Класс — чертёж нового типа: он описывает, какие данные (поля) и какие функции (методы) будут у объектов. Объект — конкретный экземпляр, созданный по этому классу, так же как x — переменная типа int, когда пишешь int x;.

C++
#include <iostream>
#include <string>

class Student {
public:
    std::string name;
    int grade = 0;

    void introduce() const {
        std::cout << name << " is in grade " << grade << '\n';
    }
};

int main() {
    Student a;
    a.name = "Aysel";
    a.grade = 8;

    Student m;
    m.name = "Murad";
    m.grade = 9;

    a.introduce();
    m.introduce();
    return 0;
}
Ожидаемый результат
Aysel is in grade 8
Murad is in grade 9
  • К членам обращаются через точку: a.name, a.introduce().
  • У каждого объекта свои данные: a и m созданы из одного класса, но имена и классы у них разные.
  • const после метода означает, что он не изменяет объект; компилятор это проверяет.

Конструкторы и деструктор

Конструктор — особый метод, который вызывается автоматически при создании объекта. Его имя совпадает с именем класса, и у него нет типа возвращаемого значения. Конструкторы, как и обычные функции, можно перегружать. Значения полям лучше всего задавать в списке инициализации — после двоеточия, перед телом: : width_(w), height_(h).

C++
#include <iostream>

class Rectangle {
public:
    Rectangle() : width_(1), height_(1) {}
    Rectangle(int w, int h) : width_(w), height_(h) {}

    int area() const { return width_ * height_; }
    int perimeter() const { return 2 * (width_ + height_); }

private:
    int width_;
    int height_;
};

int main() {
    Rectangle tile;
    Rectangle room(4, 3);
    std::cout << "Tile area: " << tile.area() << '\n';
    std::cout << "Room area: " << room.area() << '\n';
    std::cout << "Room perimeter: " << room.perimeter() << '\n';
    return 0;
}
Ожидаемый результат
Tile area: 1
Room area: 12
Room perimeter: 14

Деструктор вызывается при уничтожении объекта: его имя начинается с ~ (~Logger). Локальный объект уничтожается, когда выходит из своей области видимости — своих фигурных скобок. Именно на этом построен принцип RAII из прошлого урока: ресурс берётся в конструкторе и освобождается в деструкторе.

C++
#include <iostream>
#include <string>

class Logger {
public:
    Logger(const std::string& name) : name_(name) {
        std::cout << "Start " << name_ << '\n';
    }
    ~Logger() {
        std::cout << "End " << name_ << '\n';
    }

private:
    std::string name_;
};

int main() {
    Logger a("A");
    {
        Logger b("B");
    }
    std::cout << "Main done\n";
    return 0;
}
Ожидаемый результат
Start A
Start B
End B
Main done
End A
b уничтожается в конце внутреннего блока, а a — в конце main.

public, private и инкапсуляция

Если бы любой код мог напрямую менять баланс банковского счёта, кто-нибудь по ошибке записал бы туда отрицательное число. Инкапсуляция скрывает данные и разрешает доступ к ним только через методы с проверками. Для этого есть спецификаторы доступа: члены public видны отовсюду, а члены private — только собственным методам класса.

C++
#include <iostream>

class BankAccount {
public:
    BankAccount(int balance) : balance_(balance) {}

    void deposit(int amount) {
        if (amount > 0) {
            balance_ += amount;
        }
    }
    bool withdraw(int amount) {
        if (amount <= 0 || amount > balance_) {
            return false;
        }
        balance_ -= amount;
        return true;
    }
    int balance() const { return balance_; }

private:
    int balance_;
};

int main() {
    BankAccount acc(100);
    acc.deposit(50);
    std::cout << std::boolalpha << acc.withdraw(500) << '\n';
    std::cout << acc.withdraw(30) << '\n';
    std::cout << "Balance: " << acc.balance() << " AZN\n";
    // acc.balance_ = 1000000;  // error: balance_ is private
    return 0;
}
Ожидаемый результат
false
true
Balance: 120 AZN
Снять 500 из 150 манатов не удалось, а 30 — удалось: 150 − 30 = 120.
СпецификаторКто имеет доступ
publicлюбой код
privateтолько методы самого класса
protectedметоды самого класса и производные классы (следующий урок)

Главное

  • Класс — чертёж нового типа, объект — его конкретный экземпляр.
  • К членам обращаются через точку; const-метод не меняет объект.
  • Конструктор вызывается автоматически при создании объекта, деструктор (~Имя) — при уничтожении.
  • Задавать значения полям лучше всего в списке инициализации.
  • private скрывает данные, а public-методы дают к ним контролируемый доступ — это инкапсуляция.

Проверь себя

Вопросов: 10. Каждый правильный ответ приносит XP.

1 / 10
Чем класс отличается от объекта?