Menu
Coddy logo textTech

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 30

Funktory 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.

challenge icon

Wyzwanie

Łatwy

Zbudujmy 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_t przechowujące liczbę wyników
    • Pole typu double przechowują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 typu int i zwraca wynik pomnożony przez mnożnik bonusowy (jako int)
    • 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 jako const, ponieważ nie modyfikuje stanu obiektu.

  • main.cpp: Wczytaj następujące dane wejściowe (każde w osobnym wierszu):
    1. Liczba graczy (rozmiar)
    2. Mnożnik bonusowy (jako double)
    3. Wyniki każdego gracza (po jednym w wierszu, tyle wyników, ile wynosi rozmiar)
    4. 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: 120

Uż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;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C++ online