Tópicos
Revisões de conceitos básicos de programação com objectos no contexto da linguagem C++.
Definição de classes: herança, namespaces, constructores, destructores.
Modos de criação de objectos: na pilha, no heap (new/delete). Utilização de variáveis que denotam objectos, referências para objectos, ponteiros para objectos. Constraste entre referências C++ e referências Java e ponteiros C++ (as referências Java correspondem a ponteiros em C++).
Definição de operadores: cuidados a ter (não definir operadores com semânticas diferentes das "habituais", por forma a evitar obscurecer o significado do programa). Operadores de entrada (>>) e saída (<<) e streams (I/O, file streams e string streams).
Conceitos básicos de STL e outros elementos do namespace std: classes mais frequentes (vector, list, map, multimap, etc.). Iteradores e algoritmos.
Enunciado
Aplicando os conceitos OO que já conhece, concretize as classes necessárias para representar a funcionalidade que se descreve de seguida. Pode ser necessária a criação de classes adicionais não descritas abaixo. Todas as classes indicadas devem pertencer ao "namespace"
arabiannights.
- Funcionalidade da lâmpada mágica (classe
MagicLamp):
Uma lâmpada mágica liberta génios quando esfregada (método rub). Os génios podem ser bem ou mal-humorados. O humor dos génios é determinado pelas condições da lâmpada: sempre que a lâmpada tiver sido esfregada um número par de vezes (sem contar a actual), o génio sai mal-humorado. A quantidade de génios disponíveis é determinada no momento de encantamento da lâmpada (criação). Depois de esgotados os génios disponíveis, já não adianta esfregar a lâmpada para obter um génio, bem ou mal-humorado: nestas condições, a lâmpada cria um pequeno demónio que responde a pedidos de forma literal mas perversa. Devido a requisitos de sustentabilidade ambiental, as normas de produção exigem que as lâmpadas sejam recarregáveis. Assim, é possível voltar a obter génios quando se esfrega a lâmpada (em número igual ao inicial). O processo de recarregamento exige apenas que um demónio seja alimentado à lâmpada (método feedDemon).
Quando se cria uma nova lâmpada é necessário indicar a quantidade inicial de génios que é possível invocar (a lâmpada cria internamente os génios e apenas retorna referências ou ponteiros para eles). É possível saber quantos génios ainda estão disponíveis na lâmpada (método nGenies ). É ainda possível saber quantas vezes a lâmpada já foi recarregada (método nDemons ). Quando se esfrega a lâmpada, deve-se indicar quantos desejos se espera que o génio realize (independentemente de o génio os poder negar).
Deve ser possível comparar duas instâncias da classe MagicLamp através do operador ==. Considera-se que duas lâmpadas são iguais se tiverem a mesma capacidade e se os valores retornados pelos métodos nGenies e nDemons forem iguais.
Nota: a lâmpada liberta apenas um génio de cada vez. - Funcionalidade do génio bem-humorado (classe
FriendlyGenie):
O génio bem-humorado concede todos os desejos que lhe forem colocados (método grantWish e retorno true), até ao limite com que foi chamado da lâmpada. Depois do limite já não são concedidos desejos (retorno false). É possível saber quantos desejos já foram concedidos (método nGrantedWishes ) e quantos ainda existem disponíveis (método nRemainingWishes ).
Nota: o génio concede apenas um desejo de cada vez. - Funcionalidade do génio mal-humorado (classe
GrumpyGenie):
O génio mal-humorado concede apenas o primeiro desejo que lhe for colocado (método grantWish e retorno true), independentemente do limite com que foi chamado da lâmpada (retorno false após o primeiro). É possível saber se o desejo já foi realizado (método nGrantedWishes retorna 1). - Funcionalidade do demónio reciclável (classe
RecyclableDemon):
O demónio concede todos os desejos que lhe forem colocados (método grantWish e retorno true), independentemente do limite com que foi chamado da lâmpada. Se o demónio for recolocado na lâmpada (para a recarregar), já não pode realizar mais desejos (retorno false). É possível saber quantos desejos já foram concedidos (método nGrantedWishes ).
Nota: o demónio concede apenas um desejo de cada vez.
Todas as classes devem ter métodos de acesso
- get e
set (quando apropriado) - para os seus atributos.
O operador
<<, aplicado aos génios e ao demónio, deve enviar para o stream de saída correspondente uma das seguintes cadeias de caracteres:
- Friendly genie has granted # wishes and still has # to grant. (# representam os contadores apropriados)
- Grumpy genie has granted a wish. / Grumpy genie has a wish to grant. (consoante já concedeu ou não o pedido)
- Recyclable demon has granted # wishes. / Demon has been recycled. (antes e depois de recarregar uma lâmpada)
A função main deve executar a seguinte sequência de operações:
- Criar uma lâmpada mágica com capacidade para 4 génios.
- Esfregar 5 vezes a lâmpada, indicando os números de desejos 2, 3, 4, 5, 1.
- Imprimir em std::cout (utilizando o operador <<) cada um dos génios.
- Pedir um desejo a cada um dos génios.
- Imprimir em std::cout (utilizando o operador <<) cada um dos génios.
- Pedir um desejo a cada um dos génios.
- Imprimir em std::cout (utilizando o operador <<) cada um dos génios.
- Colocar o demónio reciclável na lâmpada.
- Esfregar a lâmpada, indicando 7 como número de desejos.
- Imprimir em std::cout (utilizando o operador <<) o génio obtido.
Resolução
Ver Arabian Nights in C++ (wiki de Compiladores).