Перегрузка операторов [] и ()
Часть раздела Объектно-ориентированное программирование путешествия по 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, когда требуется настраиваемое поведение, запоминающее значения конфигурации.
Задание
ЛегкоДавайте создадим класс ScoreTracker, который сочетает в себе операторы индексации и вызова функции. Этот класс будет хранить очки игроков и позволять получать к ним доступ по индексу с помощью [], а также будет работать как функтор, применяющий бонусный множитель к любому переданному ему значению очков.
Для организации кода вы создадите два файла:
ScoreTracker.h: Определите классScoreTracker, который управляет массивом очков игроков и может применять бонусы. Ваш класс должен содержать:- Динамически выделяемый массив
int*для хранения очков - Член типа
size_tдля хранения количества очков - Член типа
doubleдля бонусного множителя - Конструктор, который принимает размер и бонусный множитель, инициализируя все очки значением 0
- Деструктор, который правильно очищает динамическую память
- Оператор индексации
[](как константную, так и неконстантную версии) для доступа к очкам по индексу - Оператор вызова функции
(), который принимает очки типаintи возвращает их, умноженными на бонусный множитель (какint) - Метод
getSize(), который возвращает количество очков
Неконстантный оператор индексации возвращает ссылку, чтобы вы могли написать
tracker[0] = 100;. Константная версия обеспечивает доступ только для чтения для константных объектов. Оператор вызова функции должен быть помечен какconst, так как он не изменяет состояние объекта.- Динамически выделяемый массив
main.cpp: Считайте следующие входные данные (каждое на отдельной строке):- Количество игроков (размер)
- Бонусный множитель (как double)
- Очки для каждого игрока (по одному на строку, в количестве, соответствующем размеру)
- Тестовое значение очков для применения бонуса
Создайте объект
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;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнер