Прежде чем читать мою статью - реши для себя, зачем ты это делаешь. Даже если ты просто нормальный человек, лишним не будет.
Если вы настоящий профессионал программирования, то зачем вы тут сидите и читайте статью на пикабу? Если вы ради интереса зашли почитать, то претензий ноль, но если вы просто захотели задушить нового пользователя Пикабу минусами, то немедленно покиньте статью, вам однозначно интересно не будет.
Классы в программировании похожи на структуры: они представляют собой пользовательские типы данных, которые содержат поля. Синтаксически ключевые слова struct и class взаимозаменяемы, однако между ними есть важное различие. В struct поля по умолчанию являются публичными, а в class — приватными. Мы будем использовать эти термины для обозначения разных подходов к организации данных.
Классы не только задают тип данных, но и определяют их поведение. Переменные такого типа называются объектами.
Объявление класса
Рассмотрим пример простой структуры, которая хранит время в часах, минутах и секундах:
Эта структура удобна, но она не проверяет корректность значений. Например, можно присвоить часам значение 42, а минутам — -5. Чтобы избежать таких ошибок, объявим класс Time.
В классе поля будут находиться в приватной области, доступ к которой ограничен. Публичная часть будет содержать конструктор для инициализации и методы для чтения значений:
Time(int h, int m, int s); // Конструктор
int GetHours() const; // Метод для получения часов
int GetMinutes() const; // Метод для получения минут
int GetSeconds() const; // Метод для получения секунд
Здесь конструктор отвечает за начальную инициализацию объекта, а методы GetHours, GetMinutes и GetSeconds объявлены как константные (с пометкой const), что означает их невозможность изменять состояние объекта.
Реализация функций
Теперь реализуем объявленные функции. Для этого можно написать их тела внутри класса или отдельно. При внешнем определении используется префикс с именем класса и двоеточием:
Time::Time(int h, int m, int s) {
// Обработка ошибочных секунд
// Обработка ошибочных минут
// Обработка ошибочных часов
int Time::GetHours() const {
int Time::GetMinutes() const {
int Time::GetSeconds() const {
Обратите внимание, что каждая функция класса работает с текущим объектом, который передаётся неявно. Этот объект доступен через указатель this.
Обработка ошибок в конструкторе
Если конструктор получает некорректные значения, он может либо сгенерировать исключение, либо скорректировать данные. Рассмотрим второй вариант:
Time::Time(int h, int m, int s) {
Теперь объекты класса Time всегда будут содержать корректное время.
Перегрузка конструкторов
Можно добавить несколько конструкторов для удобства. Например, конструктор без параметров и конструктор, принимающий общее количество секунд:
Time() = default; // Конструктор по умолчанию
Time(int h, int m, int s); // Основной конструктор
Time(int s): Time(0, 0, s) {} // Делегирующий конструктор
Изменение состояния объекта
Чтобы позволить изменять объект после создания, добавим метод AddSeconds:
Normalize(); // Корректировка времени
Этот метод нельзя вызвать для константного объекта, так как он изменяет состояние.
Перегрузка операторов
Для удобства можно перегрузить операторы, такие как += и +. Например:
Time& operator += (int s) {
Time operator + (int s) const {
return Time(hours, minutes, seconds + s);
Теперь можно писать t += 40 или t + 20.
Ввод и вывод
Операторы << и >> можно перегрузить для работы с потоками:
std::ostream& operator << (std::ostream& out, const Time& t) {
out << t.GetHours() << ":" << t.GetMinutes() << ":" << t.GetSeconds();
std::istream& operator >> (std::istream& in, Time& t) {
in >> h >> dummy >> m >> dummy >> s;
Теперь можно легко читать и выводить время.
Модификация реализации
Интерфейс класса остаётся неизменным, даже если внутренняя реализация меняется. Например, вместо трёх полей (hours, minutes, seconds) можно хранить только одно поле totalSeconds:
const int secondsInDay = 24 * 60 * 60;
totalSeconds %= secondsInDay;
totalSeconds += secondsInDay;
Time(int h, int m, int s) {
totalSeconds = h * 60 * 60 + m * 60 + s;
return totalSeconds / (60 * 60);
return (totalSeconds / 60) % 60;
return totalSeconds % 60;
Это упрощает код, сохраняя совместимость с существующими программами.
Таким образом, классы позволяют создавать надёжные и гибкие типы данных, которые легко модифицировать и расширять.
Задание 1: Класс Point
Создайте класс Point, который представляет точку в двумерном пространстве с координатами (x, y). Реализуйте следующие функциональности:
Приватные поля x и y.
Конструкторы :
Методы доступа :
Перегрузка операторов :
Дополнительно : добавьте метод DistanceTo(const Point& other), который вычисляет расстояние между текущей точкой и другой точкой.
Задание 2: Класс Fraction
Реализуйте класс Fraction, представляющий дробь вида a/b (где a — числитель, b — знаменатель). Добавьте следующие возможности:
Приватные поля numerator и denominator.
Конструкторы :
Методы доступа :
GetNumerator() и GetDenominator().
Метод Simplify(), который сокращает дробь до несократимой формы (например, 4/8 → 1/2).
Перегрузка операторов :
Перегрузите операторы +, -, *, / для выполнения арифметических операций с дробями.
Перегрузите операторы сравнения (==, !=, <, >, <=, >=).
Дополнительно : добавьте метод ToDouble(), который возвращает значение дроби как число типа double.
Задание 3: Класс BankAccount
Создайте класс BankAccount, моделирующий банковский счёт. Реализуйте следующие функциональности:
Приватные поля :
Конструкторы :
Конструктор с начальным балансом и номером счёта.
Конструктор без параметров (начальный баланс = 0, номер счёта генерируется автоматически).
Методы :
Deposit(double amount) для пополнения счёта.
Withdraw(double amount) для снятия денег (с проверкой на достаточность средств).
GetBalance() для получения текущего баланса.
Перегрузка операторов :
Дополнительно : добавьте метод Transfer(BankAccount& other, double amount), который переводит деньги с одного счёта на другой.
Задание 4: Класс Date
Реализуйте класс Date, представляющий дату в формате день-месяц-год. Добавьте следующие возможности:
Приватные поля :
Конструкторы :
Конструктор с тремя параметрами для инициализации дня, месяца и года.
Конструктор без параметров (текущая дата по умолчанию).
Методы :
GetDay(), GetMonth(), GetYear() для получения значений.
SetDate(int day, int month, int year) для изменения даты.
IsValid() для проверки корректности даты (например, 31 февраля недопустимо).
Перегрузка операторов :
Дополнительно : добавьте метод DaysBetween(const Date& other), который возвращает количество дней между текущей датой и другой датой.
Задание 5: Класс Matrix
Создайте класс Matrix, представляющий матрицу чисел. Реализуйте следующие функциональности:
Приватные поля :
Конструкторы :
Методы :
GetElement(int row, int col) и SetElement(int row, int col, int value) для доступа к элементам.
Print() для вывода матрицы на экран.
Перегрузка операторов :
Дополнительно : добавьте метод Transpose(), который возвращает транспонированную матрицу.
Задание 6: Класс Student
Создайте класс Student, представляющий студента с информацией о его имени, возрасте и оценках. Реализуйте следующие функциональности:
Приватные поля :
name (имя студента).
age (возраст студента).
grades (массив оценок).
Конструкторы :
Конструктор с именем, возрастом и массивом оценок.
Конструктор только с именем (остальные поля по умолчанию).
Методы :
GetName(), GetAge(), GetGrades() для получения данных.
AddGrade(int grade) для добавления новой оценки.
AverageGrade() для вычисления средней оценки.
Перегрузка операторов :
Дополнительно : добавьте метод IsExcellentStudent(), который возвращает true, если средняя оценка >= 4.5.
Задание 7: Класс String
Реализуйте свой собственный класс String, аналогичный стандартному std::string. Добавьте следующие возможности:
Приватные поля :
Конструкторы :
Методы :
Length() для получения длины строки.
Concat(const String& other) для конкатенации строк.
Substring(int start, int length) для получения подстроки.
Перегрузка операторов :
Дополнительно : реализуйте метод Find(char c), который возвращает индекс первого вхождения символа в строку.