Definindo Structs Opacas
Parte da seção Programação Orientada a Objetos do Journey de C da Coddy. Lição 18 de 61.
Agora que você entende o conceito de ponteiros opacos, vamos ver como completar o padrão. O cabeçalho declara que um tipo existe, mas é no arquivo-fonte que você define o que realmente há dentro dele.
Aqui está a configuração completa. Primeiro, o cabeçalho contendo apenas a declaração antecipada:
// counter.h
#ifndef COUNTER_H
#define COUNTER_H
typedef struct Counter Counter; // tipo incompleto
Counter *create_counter(int start);
void free_counter(Counter *c);
#endif
Em seguida, o arquivo-fonte contém a definição real da struct:
// counter.c
#include "counter.h"
#include <stdlib.h>
struct Counter {
int value; // Oculto do exterior!
int step;
};
Counter *create_counter(int start) {
Counter *c = malloc(sizeof(Counter));
c->value = start;
c->step = 1;
return c;
}
void free_counter(Counter *c) {
free(c);
}
O ponto principal: struct Counter { ... } aparece somente no arquivo .c. Qualquer arquivo que inclua counter.h sabe que Counter existe, mas não consegue ver value nem step. Tentar escrever c->value em main.c causaria um erro do compilador: os membros são realmente invisíveis.
Essa separação é a base do encapsulamento em C. O próximo passo é fornecer acesso controlado por meio de funções getter e setter.
Desafio
FácilVamos criar um módulo Timer que demonstra o padrão de ponteiro opaco. Você praticará ocultar a definição da struct dentro do arquivo de origem, tornando seus membros internos completamente invisíveis para qualquer código que use o módulo.
Você criará três arquivos:
timer.h: Esta é sua interface pública. Declare um tipoTimeropaco usando apenas uma declaração antecipada: nenhum corpo de struct aqui! Declare também duas funções:create_timer(recebe um inteiro para os segundos e retorna um ponteiro para Timer) efree_timer(recebe um ponteiro para Timer e faz a limpeza). Use guardas de inclusão com o símboloTIMER_H.timer.c: É aqui que o segredo vive. Defina astruct Timerreal com dois membros ocultos:int secondseint running(use 1 para em execução e 0 para parado). Implemente seu construtor para alocar a struct, inicializarsecondscom o valor fornecido e definirrunningcomo 1. Implemente o destrutor para liberar a memória.main.c: Use seu módulo Timer para criar um temporizador e confirmar que ele foi criado com sucesso. Como os membros da struct estão ocultos, você não pode acessá-los diretamente. Esse é o objetivo! Simplesmente imprima uma mensagem confirmando a criação, depois libere o temporizador e imprima uma mensagem de limpeza.
Você receberá uma entrada: o número de segundos (um inteiro) com o qual inicializar o temporizador.
Em seu arquivo principal, crie um temporizador com o valor de segundos fornecido. Imprima uma mensagem de criação, depois libere o temporizador e imprima uma confirmação.
Imprima a saída neste formato:
Timer created
Timer freedA principal ideia aqui é que main.c pode trabalhar com ponteiros para Timer, mas não tem como acessar seconds ou running diretamente. Tentar escrever t->seconds em main.c causaria um erro do compilador, pois o corpo da struct só é definido em timer.c. Isso é encapsulamento verdadeiro: os detalhes da implementação ficam completamente ocultos para os usuários do seu módulo.
Experimente você mesmo
#include <stdio.h>
#include "timer.h"
int main() {
int seconds;
scanf("%d", &seconds);
// TODO: Crie um timer com o valor de segundos fornecido
// TODO: Print "Timer created"
// TODO: Libere o timer
// TODO: Imprima "Timer freed"
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 Conta3Ciclo 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