Iteração polimórfica
Parte da seção Programação Orientada a Objetos do Journey de C da Coddy. Lição 42 de 61.
Você aprendeu a criar interfaces e implementá-las com diferentes funções concretas. O verdadeiro benefício vem quando você consegue tratar uma coleção de objetos diferentes de maneira uniforme: percorrendo-os e chamando o mesmo ponteiro de função em cada um, independentemente do comportamento específico que esteja associado.
Imagine que você tem um array de structs Action, cada uma com sua própria função execute atribuída:
typedef void (*ExecuteFunc)(void);
typedef struct {
const char* name;
ExecuteFunc execute;
} Action;
void jump(void) { printf("Jumping!\n"); }
void run(void) { printf("Running!\n"); }
void rest(void) { printf("Resting...\n"); }Você pode criar um array dessas ações, cada uma associada a uma função diferente, e então percorrê-las com um loop for simples:
int main() {
Action actions[3] = {
{ "Jump", jump },
{ "Run", run },
{ "Rest", rest }
};
for (int i = 0; i < 3; i++) {
printf("%s: ", actions[i].name);
actions[i].execute();
}
return 0;
}O loop não sabe nem se importa com o que cada ação faz internamente. Ele simplesmente chama execute() em cada elemento.
Isso é polimorfismo em ação: o mesmo código lida com objetos que têm comportamentos completamente diferentes. Para adicionar um novo tipo de ação, não é preciso fazer nenhuma alteração na lógica de iteração; basta adicionar outro elemento ao array.
Desafio
FácilVamos criar um sistema de gerenciamento de Task que demonstra a iteração polimórfica: processar uma coleção de objetos que compartilham uma interface comum, mas executam comportamentos diferentes.
Você organizará seu código em três arquivos:
task.h: Defina aqui sua interface de tarefas. Crie um tipo de ponteiro para função chamadoTaskFuncque não recebe parâmetros e não retorna nada. Em seguida, defina uma estruturaTaskque contém umname(umconst char*) e um ponteiro para funçãorundo tipoTaskFunc.task.c: Implemente três funções de tarefa diferentes que representam diferentes tipos de trabalho:backup_task: exibeBacking up data...cleanup_task: exibeCleaning up files...report_task: exibeGenerating report...
main.c: Reúna tudo aqui. Crie um array de estruturasTask, cada uma associada a uma função de tarefa diferente. Em seguida, percorra o array e execute cada tarefa de forma polimórfica: para cada tarefa, exiba seu nome e depois chame sua funçãorun.
Seu programa receberá uma única entrada: o número de tarefas a executar (1, 2 ou 3).
Crie um array contendo exatamente três tarefas nesta ordem: uma tarefa de backup chamada Backup, uma tarefa de limpeza chamada Cleanup e uma tarefa de relatório chamada Report. Com base na quantidade informada, percorra apenas essa quantidade de tarefas desde o início do array.
Para cada tarefa na iteração, exiba o nome da tarefa seguido de dois-pontos e um espaço, e então chame sua função run.
Exemplo de saída quando a entrada é 2:
Backup: Backing up data...
Cleanup: Cleaning up files...Exemplo de saída quando a entrada é 3:
Backup: Backing up data...
Cleanup: Cleaning up files...
Report: Generating report...A ideia principal é que seu loop não precisa saber o que cada tarefa faz. Ele simplesmente exibe o nome e chama run() em cada elemento. O mesmo código de iteração trata todos os tipos de tarefa de maneira uniforme. Lembre-se de usar guardas de inclusão no arquivo de cabeçalho.
Experimente você mesmo
#include <stdio.h>
#include "task.h"
// Declare as funções de tarefa implementadas em task.c
void backup_task(void);
void cleanup_task(void);
void report_task(void);
int main() {
int count;
scanf("%d", &count);
// TODO: Crie um array de 3 structs Task nesta ordem:
// 1. Tarefa de backup chamada "Backup" usando backup_task
// 2. Tarefa de limpeza chamada "Cleanup" usando cleanup_task
// 3. Tarefa de relatório chamada "Report" usando report_task
// TODO: Percorra 'count' tarefas do array
// Para cada tarefa, imprima: "<name>: " e depois chame sua função run
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 da Programação Modular
Arquivos de cabeçalhoProteções de inclusãoArquivos-fonteFunções estáticasRevisão: calculadora modular4Encapsulamento
Conceito de ponteiros opacosDefinindo structs opacasGetters e settersValidação em settersRevisão: caixa secreta2Objetos e métodos
Structs como objetosO ponteiro 'Self'Correção de constPonteiro vs. valorMétodos auxiliaresRevisão: Gerenciador de pontos5Projeto: Conta Bancária Simples
Configuração do ProjetoImplementação da Conta8Polimorfismo
Ponteiros para funções em structsSimulando métodosO conceito de interfaceImplementando interfacesIteração polimórficaRevisão: Greeter3Ciclo de vida do objeto
Padrão de construtorPadrão de destrutorInicialização da pilhaCópia profundaRevisão: wrapper de String6Herança por composição
Incorporação de structRegra do primeiro membroAcessando membros do tipo paiUpcastingRevisão: hierarquia de formas9Projeto: Desenhador de Formas
Visão geral do projetoImplementação do círculoImplementação do retânguloUso polimórficoContêiner de formasPratique por conta própria: Compilador de C online