Sovraccarico degli operatori [] e ()
Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 45 di 104.
L’operatore di indicizzazione ([]) permette alla tua classe di comportarsi come un array, fornendo accesso indicizzato agli elementi. L’operatore di chiamata di funzione (()) trasforma gli oggetti in entità richiamabili, note come functor.
Ecco un semplice wrapper per un array con l’operatore di indicizzazione:
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];
}
};Nota che forniamo due versioni: una restituisce un riferimento non const (consentendo la modifica) e la versione const funziona con oggetti const. Questo ti permette di scrivere arr[0] = 5; per leggere e scrivere.
L'operatore di chiamata di funzione crea oggetti che possono essere «chiamati» come funzioni:
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); // Restituisce 30I funtori sono potenti perché possono mantenere lo stato tra una chiamata e l’altra, a differenza delle funzioni normali. Sono comunemente usati con gli algoritmi STL quando serve un comportamento personalizzabile che memorizzi i valori di configurazione.
Sfida
FacileCreiamo una classe ScoreTracker che combina sia l’operatore di indicizzazione sia l’operatore di chiamata di funzione. Questa classe memorizzerà i punteggi dei giocatori e ti permetterà di accedervi tramite indice usando [], funzionando anche come funtore che applica un moltiplicatore bonus a qualsiasi punteggio le venga passato.
Creerai due file per organizzare il codice:
ScoreTracker.h: definisci una classeScoreTrackerche gestisce un array di punteggi dei giocatori e può applicare bonus. La classe deve avere:- Un array
int*allocato dinamicamente per memorizzare i punteggi - Un membro
size_tper il numero di punteggi - Un membro
doubleper il moltiplicatore bonus - Un costruttore che accetta la dimensione e il moltiplicatore bonus e inizializza tutti i punteggi a 0
- Un distruttore che libera correttamente la memoria dinamica
- L’operatore di indicizzazione
[](sia nella versione const sia in quella non-const) per accedere ai punteggi tramite indice - L’operatore di chiamata di funzione
()che accetta un punteggiointe restituisce il punteggio moltiplicato per il moltiplicatore bonus (comeint) - Un metodo
getSize()che restituisce il numero di punteggi
L’operatore di indicizzazione non-const restituisce un riferimento, così puoi scrivere
tracker[0] = 100;. La versione const consente l’accesso in sola lettura agli oggetti const. L’operatore di chiamata di funzione deve essere contrassegnato comeconstperché non modifica lo stato dell’oggetto.- Un array
main.cpp: leggi i seguenti input (ciascuno su una riga separata):- Numero di giocatori (dimensione)
- Moltiplicatore bonus (come double)
- Punteggi di ciascun giocatore (uno per riga, tanti quanti indicati dalla dimensione)
- Un punteggio di prova a cui applicare il bonus
Crea un
ScoreTracker, usa l’operatore di indicizzazione per memorizzare il punteggio di ciascun giocatore, quindi mostra tutti i punteggi. Infine, usa l’operatore di chiamata di funzione per calcolare il punteggio con il bonus applicato.Formato dell’output:
Player 0: <score> Player 1: <score> ... Bonus applied to <test_score>: <result>
Per esempio, con 3 giocatori, un moltiplicatore di 1.5, punteggi di 100, 200, 150 e un punteggio di prova di 80:
Player 0: 100
Player 1: 200
Player 2: 150
Bonus applied to 80: 120Usa std::stoi() e std::stod() per convertire l’input. Non dimenticare le protezioni anti-inclusione nel file header.
Provalo tu
#include <iostream>
#include <string>
#include "ScoreTracker.h"
using namespace std;
// TODO: Implementare il costruttore di ScoreTracker
ScoreTracker::ScoreTracker(size_t size, double multiplier) {
// TODO: Inizializzare i membri e allocare un array dinamico
// Inizializzare tutti i punteggi a 0
}
// TODO: Implementare il distruttore di ScoreTracker
ScoreTracker::~ScoreTracker() {
// TODO: Liberare la memoria dinamica
}
// TODO: Implementare l'operatore di indicizzazione non const
// TODO: Implementare l'operatore di indicizzazione const
// TODO: Implementare l'operatore di chiamata di funzione
// TODO: Implementare il metodo getSize
size_t ScoreTracker::getSize() const {
// TODO: Restituire il numero di punteggi
}
int main() {
string line;
// Leggere il numero di giocatori
getline(cin, line);
size_t numPlayers = stoi(line);
// Leggere il moltiplicatore del bonus
getline(cin, line);
double multiplier = stod(line);
// TODO: Crea ScoreTracker con numPlayers e multiplier
// TODO: Leggi i punteggi di ogni giocatore e memorizzali usando l'operatore di indicizzazione
// TODO: Leggi il punteggio di prova
// TODO: Mostra i punteggi di tutti i giocatori nel formato: "Player X: <score>"
// TODO: Mostra il risultato dopo l'applicazione del bonus nel formato: "Bonus applied to <test_score>: <result>"
return 0;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniBuild e compilazione in C++File header e file sorgenteNamespace e ambitoIntroduzione alla programmazione orientata agli oggetti in C++Classi e oggetti a confrontoIl puntatore 'this'Metodi (funzioni membro)Attributi (membri dati)Fondamenti di costruttori e distruttoriRiepilogo - Calcolatrice semplice4Proprietà delle classi
Membri di istanza e staticiGetter e setterFunzioni membro constParola chiave mutableMetodi e variabili staticiFunzioni e classi friendRiepilogo - Gestore di conti bancari7Ereditarietà
Ereditarietà di baseLivelli di accesso nell’ereditarietàOrdine di chiamata di costruttori e distruttoriRidefinizione dei metodiFunzioni virtuali e VTableEreditarietà multiplaEreditarietà virtualeRiepilogo - Gerarchia dei dipendenti2Gestione della memoria
Memoria Stack vs HeapPuntatori e riferimentiMemoria dinamica (new/delete)Puntatori intelligenti in C++RAII in C++Riepilogo - Gestore di array dinamico5Incapsulamento
Specificatori di accesso in C++Specificatori di accesso in dettaglioOccultamento delle informazioniStruct vs classClassi annidate e interneRiepilogo - Sistema di registrazione degli studenti8Polimorfismo
Polimorfismo a compile time e a runtimeOverload delle funzioniFunzioni virtuali: ripassoFunzioni virtuali pureClassi astratteProgettazione delle interfacce in C++Dynamic casting e RTTIRipasso: calcolatrice di forme11Concetti avanzati di OOP
Composizione vs ereditarietàMixin tramite CRTPIdiom PimplType ErasureEnum class e tipizzazione forteGestione delle eccezioni in OOPGerarchie personalizzate di eccezioni14Pattern di progettazione - Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeRAII come pattern3Costruttori e distruttori
Costruttore predefinitoCostruttore con parametriCostruttore di copiaCostruttore di spostamentoListe di inizializzazione dei costruttoriCostruttori delegantiApprofondimento sui distruttoriRegola del Tre / Cinque / ZeroRipasso - classe String6Sovraccarico degli operatori
Introduzione al sovraccarico degli operatoriSovraccarico degli operatori aritmeticiSovraccarico degli operatori di confrontoOperatori di flussoSovraccarico dell'operatore di assegnazioneSovraccarico degli operatori [] e ()Operatori di conversione di tipoRipasso - Classe Matrix9Template
Template di funzioneTemplate di classeSpecializzazione dei templateTemplate variadiciBasi di SFINAE e dei trait di tipoRiepilogo - Contenitore genericoEsercitati da solo: Compilatore C++ online