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 surge quando você pode tratar uma coleção de objetos diferentes de maneira uniforme: iterando por eles e chamando o mesmo ponteiro de função em cada um, independentemente de qual comportamento específico esteja associado.
Imagine que você tenha um array de structs Action, cada um 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 percorrer o array com um simples loop for:
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 com comportamentos completamente diferentes. Adicionar um novo tipo de ação não exige alterações na lógica de iteração; basta adicionar outro elemento ao array.
Desafio
FácilVamos criar um sistema de gerenciamento de Task que demonstra 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 sua interface de tarefas aqui. Crie um tipo de ponteiro de função chamadoTaskFuncque não recebe parâmetros e não retorna nada. Em seguida, defina uma estruturaTaskcontendo umname(umconst char*) e um ponteiro de funçãorundo tipoTaskFunc.task.c: Implemente três funções de tarefa diferentes que representem diferentes tipos de trabalho:backup_task: imprimeBacking up data...cleanup_task: imprimeCleaning up files...report_task: imprimeGenerating 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, imprima seu nome e depois chame sua funçãorun.
Seu programa receberá uma única entrada: o número de tarefas a serem executadas (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 somente essa quantidade de tarefas a partir do início do array.
Para cada tarefa na sua iteração, imprima o nome da tarefa seguido por dois-pontos e um espaço; em seguida, 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 principal ideia é que seu loop não precisa saber o que cada tarefa faz. Ele simplesmente imprime o nome e chama run() em cada elemento. O mesmo código de iteração lida uniformemente com todos os tipos de tarefa. Lembre-se de usar guardas de inclusão no seu 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: Itere por 'count' tarefas do array
// Para cada tarefa, imprima: "<name>: " e então 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çalhoInclude GuardsArquivos-FonteFunções EstáticasRecapitulação: Calculadora Modular4Encapsulamento
Conceito de Ponteiros OpacosDefinindo Structs OpacasGetters e SettersValidação em SettersRecapitulação: Caixa Secreta2Objetos e Métodos
Structs como ObjetosO Ponteiro 'Self'Const CorrectnessPonteiro vs ValorMétodos AuxiliaresRecapitulação: Point Manager5Projeto: Conta Bancária Simples
Configuração do ProjetoImplementação da Conta8Polimorfismo
Ponteiros de Função em StructsSimulando MétodosO Conceito de InterfaceImplementando InterfacesIteração PolimórficaRecapitulação: Greeter3Ciclo de Vida de Objetos
Padrão de ConstrutorPadrão de DestrutorInicialização na StackCópia ProfundaRecapitulação: String Wrapper6Herança via Composição
Incorporação de StructsA Regra do Primeiro MembroAcessando Membros PaiUpcastingRecapitulação: Hierarquia de Formas9Projeto: Desenhador de Formas
Visão Geral do ProjetoImplementação do CírculoImplementação do RetânguloUso PolimórficoContainer de FormasPratique por conta própria: Compilador de C online