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.
Desafio
FácilVamos 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 chamadoSpeakFuncque não recebe parâmetros e não retorna nada. Em seguida, defina uma structSpeakercontendo umname(umconst char*) e um ponteiro para funçãospeakdo tipoSpeakFunc.main.c: Inclua seu cabeçalho e implemente três funções de fala diferentes:bark: imprimeWoof!meow: imprimeMeow!chirp: imprimeChirp!
Speaker, cada uma associada a uma função diferente com base na entrada, e chame seus métodosspeakpara 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;
}
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