O Conceito de Interface
Parte da seção Programação Orientada a Objetos do Journey de C da Coddy. Lição 40 de 61.
Até agora, nossas structs misturaram dados e comportamento: um nome junto com um ponteiro de função, por exemplo. Mas e se uma struct contivesse apenas ponteiros de função? Isso cria algo poderoso: uma interface.
Uma interface define quais operações estão disponíveis sem especificar como elas funcionam. É um contrato que diz: "qualquer objeto que implemente essa interface deve fornecer essas funções."
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;A struct ILogger não contém nada além de um ponteiro para função. Ela não possui dados próprios. Ela descreve puramente um comportamento. O prefixo "I" é uma convenção comum que indica que se trata de uma interface.
Qualquer código que aceite um ILogger não se importa com o destino da mensagem de log. Ela poderia usar print no console, gravar em um arquivo ou enviar dados por uma rede. Quem chama só sabe que pode chamar log:
void process(ILogger* logger, const char* msg) {
logger->log(msg); // Não sabemos COMO ele loga
}Essa separação é a essência do polimorfismo. A função process funciona com qualquer implementação de logger. Você pode trocar os comportamentos sem alterar o código da função. Na próxima lição, você criará implementações concretas que cumprem este contrato de interface.
Desafio
FácilVamos criar uma interface ICalculator: uma struct que contém apenas ponteiros para funções, definindo quais operações qualquer calculadora deve oferecer sem especificar como elas funcionam.
Você criará dois arquivos para organizar seu código:
calculator.h: Defina sua interface aqui. Crie um tipo de ponteiro para função chamadoBinaryOpque recebe dois parâmetrosinte retorna umint. Em seguida, defina uma structICalculatorque contenha apenas dois ponteiros para funções:operate(do tipoBinaryOp) edescribe(um ponteiro para função que não recebe parâmetros e não retorna nada). Essa struct é puramente uma interface. Ela não contém dados, apenas comportamento.main.c: Inclua seu header e implemente funções concretas que possam cumprir a interface:add: retorna a soma de dois inteirosmultiply: retorna o produto de dois inteirosdescribe_add: imprimeAdditiondescribe_multiply: imprimeMultiplication
ICalculator, configure-a com base na entrada e use-a para realizar um cálculo.
Seu programa receberá três entradas: dois inteiros e um código de operação (1 para adição, 2 para multiplicação).
Com base no código de operação, configure seu ICalculator com o par apropriado de funções. Em seguida, chame describe por meio da interface para imprimir o nome da operação e, depois, chame operate para calcular e imprimir o resultado.
Exemplo de saída quando as entradas são 5, 3 e 1:
Addition
8Exemplo de saída quando as entradas são 4, 7 e 2:
Multiplication
28A principal ideia é que sua struct ICalculator define um contrato: qualquer código que a utilize sabe que pode chamar describe e operate, sem saber quais funções específicas estão configuradas. Lembre-se de usar include guards no seu arquivo de header.
Experimente você mesmo
#include <stdio.h>
#include "calculator.h"
// TODO: Implemente a função add
// Retorna a soma de dois inteiros
// TODO: Implemente a função multiply
// Retorna o produto de dois inteiros
// TODO: Implemente a função describe_add
// Imprime "Addition"
// TODO: Implemente a função describe_multiply
// Prints "Multiplication"
int main() {
int num1, num2, op_code;
scanf("%d", &num1);
scanf("%d", &num2);
scanf("%d", &op_code);
// TODO: Crie uma instância de ICalculator
// TODO: Com base no op_code (1 para add, 2 para multiply),
// conecte a calculadora com as funções apropriadas
// TODO: Chame describe através da interface
// TODO: Chame operate através da interface e imprima o resultado
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