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 criar uma classe ScoreTracker que combina os operadores de subscrito e de chamada de função. Essa classe armazenará as pontuações dos jogadores e permitirá que você as acesse por índice usando [], além de atuar como um funtor que aplica um multiplicador de bônus a qualquer pontuação que você passar para ela.
Você criará dois arquivos para organizar seu código:
ScoreTracker.h: defina uma classeScoreTrackerque gerencie um array de pontuações dos jogadores e possa aplicar bônus. Sua classe deve ter:- Um array
int*alocado dinamicamente para armazenar as pontuações - Um membro
size_tpara a quantidade de pontuações - Um membro
doublepara o multiplicador de bônus - Um construtor que receba o tamanho e o multiplicador de bônus, inicializando todas as pontuações com 0
- Um destrutor que libere corretamente a memória dinâmica
- O operador de subscrito
[](nas versões const e não-const) para acessar as pontuações por índice - O operador de chamada de função
(), que receba uma pontuaçãointe retorne a pontuação multiplicada pelo multiplicador de bônus (como umint) - Um método
getSize()que retorne a quantidade 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 somente para leitura a 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 de cada jogador (uma por linha, em quantidade igual ao tamanho)
- Uma pontuação de teste à qual 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 da 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 igual a 80:
Player 0: 100
Player 1: 200
Player 2: 150
Bonus applied to 80: 120Use std::stoi() e std::stod() para a conversão das entradas. Não se esqueça dos guards de inclusão no arquivo de cabeçalho.
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 POO
Arquivos externosBuild e compilação em C++Arquivos de cabeçalho e arquivos-fonteNamespaces e escopoIntrodução à POO em C++Classes vs. objetosO ponteiro 'this'Métodos (funções membro)Atributos (membros de dados)Noções básicas de construtores e destruidoresRevisão - calculadora simples4Propriedades de Classe
Membros de Instância vs. EstáticosGetters e SettersFunções Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRevisão - Gerenciador de Contas Bancárias7Herança
Herança básicaNíveis de acesso da herançaOrdem de chamada de construtor e destrutorSobrescrita de métodosFunções virtuais e VTableHerança múltiplaHerança virtualRevisão - Hierarquia de funcionários10Visão geral da STL
Visão geral e filosofia da STLContêineres da STLIteradoresAlgoritmos da STLFunctors e expressões lambdaRecapitulação - Frequência de palavras13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonFactory e Abstract FactoryPadrão BuilderPadrão ObserverPadrão Strategy2Gerenciamento de Memória
Memória Stack vs. HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Ponteiros Inteligentes em C++RAII em C++Revisão - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de acesso em C++Especificadores de acesso em profundidadeOcultação de informaçõesStruct vs ClasseClasses aninhadas e internasRecapitulação - Sistema de registros de alunos8Polimorfismo
Polimorfismo em compilação vs. execuçãoSobrecarga de funçõesFunções virtuais revisadasFunções virtuais purasClasses abstratasDesign de interfaces em C++Conversão dinâmica e RTTIRecapitulação — Calculadora de formas11Conceitos Avançados de OOP
Composição vs. HerançaMixins via CRTPIdioma PimplApagamento de TiposClasses Enum e Tipagem ForteTratamento de Exceções em OOPHierarquias de Exceções Personalizadas14Padrões de Projeto — Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositeRAII como Padrão3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentoListas de Inicialização do ConstrutorConstrutores DelegantesAprofundamento em DestrutoresRegra dos Três / Cinco / ZeroRevisão - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de FluxoSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçõesTemplates de ClassesEspecialização de TemplatesTemplates VariádicosNoções Básicas de SFINAE e Traits de TiposRecapitulação - Contêiner GenéricoPratique por conta própria: Compilador de C++ online