Menu
Coddy logo textTech

Simulando Métodos

Parte da seção Programação Orientada a Objetos do Journey de C da Coddy. Lição 39 de 61.

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

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

typedef void (*ActionFunc)(void);

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

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

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 um comportamento que varia por instância.

Esse 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 criar um sistema de Speaker que demonstre como diferentes instâncias do mesmo tipo de struct podem apresentar comportamentos completamente diferentes, dependendo de qual função está associada a elas.

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

  • speaker.h: Defina um tipo de ponteiro para 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 para 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 associada a uma função diferente com base na entrada, e chame seus métodos speak para observar o comportamento polimórfico em ação.

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

Crie duas instâncias de Speaker. Você pode nomeá-las como quiser (por exemplo, "Dog", "Cat", "Bird" ou simplesmente "Speaker1", "Speaker2"). Associe cada uma à função apropriada com base no código de entrada e, em seguida, chame speak em cada instância, nessa 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 principal ideia aqui é que ambos os speakers 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 include guards no seu arquivo de cabeçalho.

Experimente você mesmo

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

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

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

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

int main() {
    int type1, type2;
    scanf("%d", &type1);
    scanf("%d", &type2);
    
    // TODO: Crie duas instâncias de Speaker
    
    // TODO: Conecte a função speak do primeiro speaker com base em type1
    // (1 = bark, 2 = meow, 3 = chirp)
    
    // TODO: Conecte a função speak do segundo speaker com base em type2
    // (1 = bark, 2 = meow, 3 = chirp)
    
    // TODO: Chame speak em cada speaker 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 Programação Orientada a Objetos

Pratique por conta própria: Compilador de C online