Menu
Coddy logo textTech

Перегрузка операторов [] и ()

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy — урок 45 из 104.

Оператор индексации ([]) позволяет вашему классу вести себя как массив, обеспечивая индексированный доступ к элементам. Оператор вызова функции (()) превращает объекты в вызываемые сущности, известные как функторы.

Вот простая обертка для массива с оператором индексации:

class IntArray {
    int* data;
    size_t size;
    
public:
    IntArray(size_t s) : size(s), data(new int[s]()) {}
    ~IntArray() { delete[] data; }
    
    int& operator[](size_t index) {
        return data[index];
    }
    
    const int& operator[](size_t index) const {
        return data[index];
    }
};

Обратите внимание, что мы предоставляем две версии: одна возвращает неконстантную ссылку (позволяя модификацию), а константная версия работает с константными объектами. Это позволяет вам писать arr[0] = 5; для чтения и записи.

Оператор вызова функции создает объекты, которые можно «вызывать» подобно функциям:

class Multiplier {
    int factor;
    
public:
    Multiplier(int f) : factor(f) {}
    
    int operator()(int value) const {
        return value * factor;
    }
};

Multiplier triple(3);
int result = triple(10);    // Возвращает 30

Функторы обладают большими возможностями, так как они могут сохранять состояние между вызовами, в отличие от обычных функций. Они часто используются с алгоритмами STL, когда требуется настраиваемое поведение, запоминающее значения конфигурации.

challenge icon

Задание

Легко

Давайте создадим класс ScoreTracker, который сочетает в себе операторы индексации и вызова функции. Этот класс будет хранить очки игроков и позволять получать к ним доступ по индексу с помощью [], а также будет работать как функтор, применяющий бонусный множитель к любому переданному ему значению очков.

Для организации кода вы создадите два файла:

  • ScoreTracker.h: Определите класс ScoreTracker, который управляет массивом очков игроков и может применять бонусы. Ваш класс должен содержать:
    • Динамически выделяемый массив int* для хранения очков
    • Член типа size_t для хранения количества очков
    • Член типа double для бонусного множителя
    • Конструктор, который принимает размер и бонусный множитель, инициализируя все очки значением 0
    • Деструктор, который правильно очищает динамическую память
    • Оператор индексации [] (как константную, так и неконстантную версии) для доступа к очкам по индексу
    • Оператор вызова функции (), который принимает очки типа int и возвращает их, умноженными на бонусный множитель (как int)
    • Метод getSize(), который возвращает количество очков

    Неконстантный оператор индексации возвращает ссылку, чтобы вы могли написать tracker[0] = 100;. Константная версия обеспечивает доступ только для чтения для константных объектов. Оператор вызова функции должен быть помечен как const, так как он не изменяет состояние объекта.

  • main.cpp: Считайте следующие входные данные (каждое на отдельной строке):
    1. Количество игроков (размер)
    2. Бонусный множитель (как double)
    3. Очки для каждого игрока (по одному на строку, в количестве, соответствующем размеру)
    4. Тестовое значение очков для применения бонуса

    Создайте объект ScoreTracker, используйте оператор индексации для сохранения очков каждого игрока, а затем выведите все очки. Наконец, используйте оператор вызова функции, чтобы рассчитать результат с применением бонуса.

    Формат вывода:

    Player 0: <score>
    Player 1: <score>
    ...
    Bonus applied to <test_score>: <result>

Например, для 3 игроков, множителя 1.5, очков 100, 200, 150 и тестового значения 80:

Player 0: 100
Player 1: 200
Player 2: 150
Bonus applied to 80: 120

Используйте std::stoi() и std::stod() для преобразования входных данных. Не забудьте про include guards (защиту от повторного включения) в заголовочном файле.

Шпаргалка

Оператор индексации [] позволяет обращаться к объектам как к массивам. Оператор вызова функции () делает объекты вызываемыми, подобно функциям (функторы).

Оператор индексации

Предоставляйте как константную, так и неконстантную версии для доступа на чтение и запись:

class IntArray {
    int* data;
    size_t size;
    
public:
    IntArray(size_t s) : size(s), data(new int[s]()) {}
    ~IntArray() { delete[] data; }
    
    // Non-const version: allows modification
    int& operator[](size_t index) {
        return data[index];
    }
    
    // Const version: read-only access
    const int& operator[](size_t index) const {
        return data[index];
    }
};

Оператор вызова функции

Создает функторы, которые могут сохранять состояние между вызовами:

class Multiplier {
    int factor;
    
public:
    Multiplier(int f) : factor(f) {}
    
    int operator()(int value) const {
        return value * factor;
    }
};

Multiplier triple(3);
int result = triple(10);    // Returns 30

Функторы полезны в алгоритмах STL, где требуется настраиваемое поведение с сохраненной конфигурацией.

Попробуйте сами

#include <iostream>
#include <string>
#include "ScoreTracker.h"

using namespace std;

// TODO: Реализовать конструктор ScoreTracker
ScoreTracker::ScoreTracker(size_t size, double multiplier) {
    // TODO: Инициализировать члены и выделить динамический массив
    // Инициализировать все баллы значением 0
}

// TODO: Реализовать деструктор ScoreTracker
ScoreTracker::~ScoreTracker() {
    // TODO: Очистить динамическую память
}

// TODO: Реализовать неконстантный оператор индексации

// TODO: Реализовать константный оператор индексации

// TODO: Реализовать оператор вызова функции

// TODO: Реализовать метод getSize
size_t ScoreTracker::getSize() const {
    // TODO: Вернуть количество баллов
}

int main() {
    string line;
    
    // Прочитать количество игроков
    getline(cin, line);
    size_t numPlayers = stoi(line);
    
    // Прочитать множитель бонуса
    getline(cin, line);
    double multiplier = stod(line);
    
    // TODO: Создать ScoreTracker с numPlayers и multiplier
    
    // TODO: Прочитать баллы для каждого игрока и сохранить их с помощью оператора индексации
    
    // TODO: Прочитать тестовый балл
    
    // TODO: Вывести баллы всех игроков в формате: "Player X: <score>"
    
    // TODO: Вывести результат применения бонуса в формате: "Bonus applied to <test_score>: <result>"
    
    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование