Menu
Coddy logo textTech

Simulando Métodos

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

Você viu como colocar um ponteiro de função dentro de uma struct. O verdadeiro poder surge quando você atribui funções diferentes a instâncias diferentes do mesmo tipo de struct — é assim que simulamos métodos com comportamentos variados.

Considere uma struct que representa uma ação com lógica customizável:

typedef void (*ActionFunc)(void);

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

Ao criar instâncias, você conecta funções diferentes a cada uma delas:

void say_hello(void) {
    printf("Hello!\n");
}

void say_goodbye(void) {
    printf("Goodbye!\n");
}

int main() {
    Action greet = { "Greet", say_hello };
    Action farewell = { "Farewell", say_goodbye };
    
    greet.execute();    // Saída: Hello!
    farewell.execute(); // Saída: Goodbye!
    return 0;
}

Tanto greet quanto farewell são do mesmo tipo (Action), mas chamar execute em cada um produz resultados completamente diferentes. A struct não apenas armazena dados — ela armazena comportamento que varia por instância.

Este padrão reflete como os objetos funcionam em outras linguagens: cada objeto pode ter sua própria implementação de um método, embora compartilhem a mesma interface.

challenge icon

Desafio

Fácil

Vamos construir um sistema Speaker que demonstra como diferentes instâncias do mesmo tipo de struct podem exibir comportamentos completamente diferentes com base em qual função está conectada a elas.

Você criará dois arquivos para organizar seu código:

  • speaker.h: Defina um tipo de ponteiro de função chamado SpeakFunc que não recebe parâmetros e não retorna nada. Em seguida, defina uma struct Speaker contendo um name (um const char*) e um ponteiro de função speak do tipo SpeakFunc.
  • main.c: Inclua seu cabeçalho e implemente três funções de fala diferentes:
    • bark — imprime Woof!
    • meow — imprime Meow!
    • chirp — imprime Chirp!
    Em seguida, crie duas instâncias de Speaker, cada uma conectada a uma função diferente com base na entrada, e chame seus métodos speak para ver o comportamento polimórfico em ação.

Seu programa receberá duas entradas: o primeiro tipo de alto-falante (1 para bark, 2 para meow, 3 para chirp) e o segundo tipo de alto-falante (também 1, 2 ou 3).

Crie duas instâncias de Speaker — você pode nomeá-las como desejar (como "Dog", "Cat", "Bird", ou simplesmente "Speaker1", "Speaker2"). Conecte cada uma à função apropriada com base em seu código de entrada e, em seguida, chame speak em cada instância em ordem.

Exemplo de saída quando o primeiro tipo é 1 e o segundo tipo é 2:

Woof!
Meow!

Exemplo de saída quando o primeiro tipo é 3 e o segundo tipo é 3:

Chirp!
Chirp!

A ideia principal aqui é que ambos os alto-falantes são do mesmo tipo Speaker, mas produzem saídas diferentes porque cada um tem uma função diferente atribuída ao seu membro speak. Lembre-se de usar guards de inclusão em seu arquivo de cabeçalho.

Folha de consulta

Diferentes instâncias do mesmo tipo de struct podem conter diferentes ponteiros de função, permitindo um comportamento polimórfico.

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

typedef void (*ActionFunc)(void);

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

Crie instâncias com diferentes funções atribuídas:

void say_hello(void) {
    printf("Hello!\n");
}

void say_goodbye(void) {
    printf("Goodbye!\n");
}

int main() {
    Action greet = { "Greet", say_hello };
    Action farewell = { "Farewell", say_goodbye };
    
    greet.execute();    // Output: Hello!
    farewell.execute(); // Output: Goodbye!
    return 0;
}

Ambas as instâncias compartilham o mesmo tipo, mas exibem comportamentos diferentes quando seus ponteiros de função são chamados.

Experimente você mesmo

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

// TODO: Implementar a função bark que imprime "Woof!"

// TODO: Implementar a função meow que imprime "Meow!"

// TODO: Implementar a função chirp que imprime "Chirp!"

int main() {
    int type1, type2;
    scanf("%d", &type1);
    scanf("%d", &type2);
    
    // TODO: Criar duas instâncias de Speaker
    
    // TODO: Conectar a função speak do primeiro alto-falante com base em type1
    // (1 = bark, 2 = meow, 3 = chirp)
    
    // TODO: Conectar a função speak do segundo alto-falante com base em type2
    // (1 = bark, 2 = meow, 3 = chirp)
    
    // TODO: Chamar speak em cada alto-falante em ordem
    
    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