Menu
Coddy logo textTech

Iteração Polimórfica

Parte da seção Object Oriented Programming do Journey de C da Coddy — lição 42 de 61.

Você aprendeu a criar interfaces e implementá-las com diferentes funções concretas. A verdadeira vantagem surge quando você pode tratar uma coleção de diferentes objetos de forma uniforme — iterando por eles e chamando o mesmo ponteiro de função em cada um, independentemente de qual comportamento específico esteja configurado.

Imagine que você tem um array de Action structs, 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 conectada 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 com comportamentos completamente diferentes. Adicionar um novo tipo de ação não requer alterações na lógica de iteração; você apenas adiciona outro elemento ao array.

challenge icon

Desafio

Fácil

Vamos construir um sistema de gerenciamento de Task que demonstra iteração polimórfica — processando 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 tarefa aqui. Crie um tipo de ponteiro de função chamado TaskFunc que não recebe parâmetros e não retorna nada. Em seguida, defina uma struct Task contendo um name (um const char*) e um ponteiro de função run do tipo TaskFunc.
  • task.c: Implemente três funções de tarefa diferentes que representam diferentes tipos de trabalho:
    • backup_task — imprime Backing up data...
    • cleanup_task — imprime Cleaning up files...
    • report_task — imprime Generating report...
  • main.c: Reúna tudo aqui. Crie um array de structs Task, cada uma vinculada a uma função de tarefa diferente. Em seguida, itere pelo array e execute cada tarefa de forma polimórfica — para cada tarefa, imprima seu nome seguido pela chamada de sua função run.

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 contagem de entrada, itere apenas por esse número de tarefas a partir do início do array.

Para cada tarefa em sua iteração, imprima o nome da tarefa seguido por 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 central é 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 com todos os tipos de tarefas uniformemente. Lembre-se de usar include guards em seu arquivo de cabeçalho.

Folha de consulta

Você pode iterar por coleções de objetos que compartilham uma interface comum, chamando o mesmo ponteiro de função em cada elemento, independentemente de sua implementação específica. Isso é polimorfismo — tratar diferentes objetos de forma uniforme.

Defina um tipo de ponteiro de função e uma struct que o utilize:

typedef void (*ExecuteFunc)(void);

typedef struct {
    const char* name;
    ExecuteFunc execute;
} Action;

Crie funções concretas que correspondam à assinatura:

void jump(void) { printf("Jumping!\n"); }
void run(void)  { printf("Running!\n"); }
void rest(void) { printf("Resting...\n"); }

Construa um array de structs, cada uma vinculada a uma função diferente, e então itere por elas:

Action actions[3] = {
    { "Jump", jump },
    { "Run", run },
    { "Rest", rest }
};

for (int i = 0; i < 3; i++) {
    printf("%s: ", actions[i].name);
    actions[i].execute();
}

O loop não precisa saber o que cada ação faz internamente — ele simplesmente chama o ponteiro de função em cada elemento. Adicionar novos tipos não requer alterações na lógica de iteração.

Experimente você mesmo

#include <stdio.h>
#include "task.h"

// Declara 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;
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Object Oriented Programming