Przeciążanie operatorów [] i ()
Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 45 z 104.
Operator indeksowania ([]) pozwala Twojej klasie zachowywać się jak tablica, zapewniając dostęp do elementów za pomocą indeksów. Operator wywołania funkcji (()) sprawia, że obiekty stają się wywoływalne — nazywa się je funktorami.
Oto prosty wrapper tablicy z operatorem indeksowania:
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];
}
};Zauważ, że udostępniamy dwie wersje: jedna zwraca referencję niebędącą const (umożliwiającą modyfikację), a wersja const działa z obiektami const. Dzięki temu możesz używać arr[0] = 5; do odczytu i zapisu.
Operator wywołania funkcji tworzy obiekty, które można „wywoływać” jak funkcje:
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); // Zwraca 30Funktory są potężne, ponieważ mogą zachowywać stan między wywołaniami, w przeciwieństwie do zwykłych funkcji. Są powszechnie używane z algorytmami STL, gdy potrzebujesz konfigurowalnego zachowania, które zapamiętuje wartości konfiguracji.
Wyzwanie
ŁatwyZbudujmy klasę ScoreTracker, która łączy operator indeksowania i operator wywołania funkcji. Klasa ta będzie przechowywać wyniki graczy i umożliwi dostęp do nich według indeksu za pomocą [], a jednocześnie będzie działać jak funktor, który stosuje mnożnik bonusowy do każdego przekazanego wyniku.
Utworzysz dwa pliki, aby uporządkować swój kod:
ScoreTracker.h: Zdefiniuj klasęScoreTracker, która zarządza tablicą wyników graczy i może stosować bonusy. Twoja klasa powinna zawierać:- Dynamicznie alokowaną tablicę
int*do przechowywania wyników - Pole typu
size_tprzechowujące liczbę wyników - Pole typu
doubleprzechowujące mnożnik bonusowy - Konstruktor przyjmujący rozmiar i mnożnik bonusowy, inicjalizujący wszystkie wyniki wartością 0
- Destruktor, który prawidłowo zwalnia pamięć dynamiczną
- Operator indeksowania
[](zarówno w wersji const, jak i nie-const) umożliwiający dostęp do wyników według indeksu - Operator wywołania funkcji
(), który przyjmuje wynik typuinti zwraca wynik pomnożony przez mnożnik bonusowy (jakoint) - Metodę
getSize(), która zwraca liczbę wyników
Operator indeksowania w wersji nie-const zwraca referencję, dzięki czemu możesz napisać
tracker[0] = 100;. Wersja const umożliwia dostęp tylko do odczytu dla obiektów const. Operator wywołania funkcji powinien być oznaczony jakoconst, ponieważ nie modyfikuje stanu obiektu.- Dynamicznie alokowaną tablicę
main.cpp: Wczytaj następujące dane wejściowe (każde w osobnym wierszu):- Liczba graczy (rozmiar)
- Mnożnik bonusowy (jako double)
- Wyniki każdego gracza (po jednym w wierszu, tyle wyników, ile wynosi rozmiar)
- Wynik testowy, do którego należy zastosować bonus
Utwórz obiekt
ScoreTracker, użyj operatora indeksowania, aby zapisać wynik każdego gracza, a następnie wyświetl wszystkie wyniki. Na koniec użyj operatora wywołania funkcji, aby obliczyć wynik z zastosowanym bonusem.Format wyjściowy:
Player 0: <score> Player 1: <score> ... Bonus applied to <test_score>: <result>
Na przykład, dla 3 graczy, mnożnika 1.5, wyników 100, 200, 150 i wyniku testowego 80:
Player 0: 100
Player 1: 200
Player 2: 150
Bonus applied to 80: 120Użyj std::stoi() i std::stod() do konwersji danych wejściowych. Nie zapomnij o strażnikach nagłówka w pliku nagłówkowym.
Spróbuj swoich sił
#include <iostream>
#include <string>
#include "ScoreTracker.h"
using namespace std;
// TODO: Zaimplementuj konstruktor ScoreTracker
ScoreTracker::ScoreTracker(size_t size, double multiplier) {
// TODO: Zainicjalizuj pola i zaalokuj tablicę dynamiczną
// Zainicjalizuj wszystkie wyniki wartością 0
}
// TODO: Zaimplementuj destruktor ScoreTracker
ScoreTracker::~ScoreTracker() {
// TODO: Zwolnij pamięć dynamiczną
}
// TODO: Zaimplementuj operator indeksowania dla obiektów innych niż const
// TODO: Zaimplementuj operator indeksowania dla obiektów const
// TODO: Zaimplementuj operator wywołania funkcji
// TODO: Zaimplementuj metodę getSize
size_t ScoreTracker::getSize() const {
// TODO: Zwróć liczbę wyników
}
int main() {
string line;
// Wczytaj liczbę graczy
getline(cin, line);
size_t numPlayers = stoi(line);
// Wczytaj mnożnik premii
getline(cin, line);
double multiplier = stod(line);
// TODO: Utwórz ScoreTracker z numPlayers i multiplier
// TODO: Odczytaj wyniki każdego gracza i zapisz je za pomocą operatora indeksowania
// TODO: Odczytaj wynik testowy
// TODO: Wyświetl wyniki wszystkich graczy w formacie: "Player X: <score>"
// TODO: Wyświetl wynik po zastosowaniu premii w formacie: "Bonus applied to <test_score>: <result>"
return 0;
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneBudowanie i kompilacja C++Pliki nagłówkowe i pliki źródłowePrzestrzenie nazw i zakresWprowadzenie do programowania obiektowego w C++Klasy a obiektyWskaźnik „this”Metody (funkcje składowe)Atrybuty (składowe danych)Podstawy konstruktorów i destruktorówPowtórzenie – prosty kalkulator4Właściwości klas
Elementy instancji a elementy statyczneGettery i setteryStałe funkcje składoweSłowo kluczowe mutableMetody i zmienne statyczneFunkcje i klasy zaprzyjaźnionePodsumowanie – menedżer konta bankowego7Dziedziczenie
Podstawy dziedziczeniaPoziomy dostępu w dziedziczeniuKolejność wywołań konstruktora i destruktoraNadpisywanie metodFunkcje wirtualne i VTableWielokrotne dziedziczenieDziedziczenie wirtualnePowtórzenie — hierarchia pracowników2Zarządzanie pamięcią
Pamięć stosu a stertyWskaźniki i referencjePamięć dynamiczna (new/delete)Inteligentne wskaźniki w C++RAII w C++Podsumowanie — menedżer tablicy dynamicznej5Hermetyzacja
Specyfikatory dostępu w C++Specyfikatory dostępu — szczegółowoUkrywanie informacjiStruktura a klasaKlasy zagnieżdżone i wewnętrznePodsumowanie — system ewidencji studentów8Polimorfizm
Polimorfizm czasu kompilacji i wykonaniaPrzeciążanie funkcjiFunkcje wirtualne — powtórkaCzysto wirtualne funkcjeKlasy abstrakcyjneProjektowanie interfejsów w C++Rzutowanie dynamiczne i RTTIPodsumowanie — kalkulator kształtów3Konstruktory i destruktory
Konstruktor domyślnyKonstruktor z parametramiKonstruktor kopiującyKonstruktor przenoszącyListy inicjalizacyjne konstruktoraKonstruktory delegująceDestruktor — szczegółowe omówienieZasada trzech / pięciu / zeraPodsumowanie — klasa String6Przeciążanie operatorów
Wprowadzenie do przeciążania operatorówPrzeciążanie operatorów arytmetycznychPrzeciążanie operatorów porównaniaOperatory strumieniowePrzeciążanie operatora przypisaniaPrzeciążanie operatorów [] i ()Operatory konwersji typówPodsumowanie — klasa Matrix9Szablony
Szablony funkcjiSzablony klasSpecjalizacja szablonówSzablony wariadycznePodstawy SFINAE i cech typówPodsumowanie — kontener generycznyPoćwicz samodzielnie: Kompilator C++ online