Sobrecarga dos Operadores [] e ()
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 45 de 104.
O operador de subscrito ([]) permite que sua classe se comporte como um array, fornecendo acesso indexado aos elementos. O operador de chamada de função (()) transforma objetos em entidades chamáveis, conhecidas como functores.
Aqui está um wrapper de array simples com o operador de subscrito:
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];
}
};Observe que fornecemos duas versões: uma retorna uma referência não-const (permitindo modificação), e a versão const funciona com objetos const. Isso permite que você escreva arr[0] = 5; para leitura e escrita.
O operador de chamada de função cria objetos que podem ser "chamados" como funções:
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); // Retorna 30Functors são poderosos porque podem manter o estado entre chamadas, ao contrário de funções regulares. Eles são comumente usados com algoritmos da STL onde você precisa de um comportamento personalizável que lembre valores de configuração.
Desafio
FácilVamos construir uma classe ScoreTracker que combina os operadores de subscrito e de chamada de função. Esta classe armazenará pontuações para jogadores e permitirá que você as acesse por índice usando [], enquanto também atuará como um functor que aplica um multiplicador de bônus a qualquer pontuação que você passar para ele.
Você criará dois arquivos para organizar seu código:
ScoreTracker.h: Defina uma classeScoreTrackerque gerencia um array de pontuações de jogadores e pode aplicar bônus. Sua classe deve ter:- Um array
int*alocado dinamicamente para armazenar as pontuações - Um membro
size_tpara o número de pontuações - Um membro
doublepara o multiplicador de bônus - Um construtor que recebe o tamanho e o multiplicador de bônus, inicializando todas as pontuações com 0
- Um destruidor que limpa adequadamente a memória dinâmica
- O operador de subscrito
[](versões const e não-const) para acessar as pontuações por índice - O operador de chamada de função
()que recebe uma pontuaçãointe retorna a pontuação multiplicada pelo multiplicador de bônus (como umint) - Um método
getSize()que retorna o número de pontuações
O operador de subscrito não-const retorna uma referência para que você possa escrever
tracker[0] = 100;. A versão const permite acesso de apenas leitura para objetos const. O operador de chamada de função deve ser marcado comoconst, pois não modifica o estado do objeto.- Um array
main.cpp: Leia as seguintes entradas (cada uma em uma linha separada):- Número de jogadores (tamanho)
- Multiplicador de bônus (como um double)
- Pontuações para cada jogador (uma por linha, tantas quanto o tamanho)
- Uma pontuação de teste para aplicar o bônus
Crie um
ScoreTracker, use o operador de subscrito para armazenar a pontuação de cada jogador e, em seguida, exiba todas as pontuações. Por fim, use o operador de chamada de função para calcular a pontuação com o bônus aplicado.Formato de saída:
Player 0: <score> Player 1: <score> ... Bonus applied to <test_score>: <result>
Por exemplo, com 3 jogadores, um multiplicador de 1.5, pontuações de 100, 200, 150 e uma pontuação de teste de 80:
Player 0: 100
Player 1: 200
Player 2: 150
Bonus applied to 80: 120Use std::stoi() e std::stod() para conversão de entrada. Não se esqueça dos header guards em seu arquivo de cabeçalho.
Folha de consulta
O operador de subscrito [] permite que objetos sejam acessados como arrays. O operador de chamada de função () torna os objetos chamáveis como funções (functors).
Operador de Subscrito
Forneça versões const e não-const para acesso de leitura/escrita:
class IntArray {
int* data;
size_t size;
public:
IntArray(size_t s) : size(s), data(new int[s]()) {}
~IntArray() { delete[] data; }
// Versão não-const: permite modificação
int& operator[](size_t index) {
return data[index];
}
// Versão const: acesso apenas de leitura
const int& operator[](size_t index) const {
return data[index];
}
};Operador de Chamada de Função
Cria functors que podem manter o estado entre as chamadas:
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); // Retorna 30Functors são úteis com algoritmos STL onde é necessário um comportamento personalizável com configuração armazenada.
Experimente você mesmo
#include <iostream>
#include <string>
#include "ScoreTracker.h"
using namespace std;
// TODO: Implementar o construtor ScoreTracker
ScoreTracker::ScoreTracker(size_t size, double multiplier) {
// TODO: Inicializar membros e alocar array dinâmico
// Inicializar todas as pontuações com 0
}
// TODO: Implementar o destrutor ScoreTracker
ScoreTracker::~ScoreTracker() {
// TODO: Limpar a memória dinâmica
}
// TODO: Implementar o operador de subscrito não-const
// TODO: Implementar o operador de subscrito const
// TODO: Implementar o operador de chamada de função
// TODO: Implementar o método getSize
size_t ScoreTracker::getSize() const {
// TODO: Retornar o número de pontuações
}
int main() {
string line;
// Ler o número de jogadores
getline(cin, line);
size_t numPlayers = stoi(line);
// Ler o multiplicador de bônus
getline(cin, line);
double multiplier = stod(line);
// TODO: Criar ScoreTracker com numPlayers e multiplier
// TODO: Ler as pontuações de cada jogador e armazenar usando o operador de subscrito
// TODO: Ler a pontuação de teste
// TODO: Exibir todas as pontuações dos jogadores no formato: "Player X: <score>"
// TODO: Exibir o resultado do bônus aplicado no formato: "Bonus applied to <test_score>: <result>"
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP
Arquivos ExternosBuild e Compilação em C++Arquivos Header e SourceNamespaces e EscopoIntrodução a OOP em C++Classes vs ObjetosO Ponteiro 'this'Métodos (Funções Membro)Atributos (Membros de Dados)Básico de Ctors e DtorsRecapitulação - Calculadora Simples4Propriedades de Classe
Membros de Instância vs EstáticosGetters e SettersFunções de Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRecapitulação - Gerenciador de Conta Bancária7Herança
Herança BásicaNíveis de Acesso na HerançaOrdem de Chamada de Ctor e DtorSobrescrita de MétodosFunções Virtuais e VTableHerança MúltiplaHerança VirtualRecapitulação - Hierarquia de Funcionários2Gerenciamento de Memória
Memória Stack vs HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Smart Pointers em C++RAII em C++Recapitulação - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de Acesso em C++Especificadores de Acesso em DetalhesOcultação de InformaçãoStruct vs ClassClasses Aninhadas e InternasRecapitulação - Sistema de Registros de Alunos8Polimorfismo
Polimorfismo de Compilação vs Tempo de ExecuçãoSobrecarga de FunçõesFunções Virtuais RevisitadasFunções Virtuais PurasClasses AbstratasDesign de Interfaces em C++Dynamic Casting e RTTIRecapitulação - Calculadora de Formas3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentaçãoListas de Inicialização do ConstrutorConstrutores DelegadosMergulho Profundo em DestrutoresRegra dos Três / Cinco / ZeroRecapitulação - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de StreamSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçãoTemplates de ClasseEspecialização de TemplatesTemplates VariádicosFundamentos de SFINAE e Type TraitsRecapitulação - Container Genérico