Menu
CoddyTech

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 ele realmente contém.

Aqui está a configuração completa. Primeiro, o cabeçalho apenas com 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 para quem está fora!
    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 apenas 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 de compilação: 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.

challenge icon

Desafio

Fácil

Vamos criar um módulo Timer que demonstra o padrão de ponteiro opaco. Você vai praticar como ocultar a definição da struct dentro do arquivo-fonte, tornando seus membros internos completamente invisíveis para qualquer código que use seu módulo.

Você vai criar três arquivos:

  • timer.h: Esta é sua interface pública. Declare um tipo opaco Timer usando apenas uma declaração antecipada: nada de corpo da struct aqui! Declare também duas funções: create_timer (recebe um número inteiro de segundos e retorna um ponteiro para Timer) e free_timer (recebe um ponteiro para Timer e faz a limpeza). Use diretivas de proteção contra inclusão duplicada com o símbolo TIMER_H.
  • timer.c: É aqui que está o segredo. Defina a struct Timer real com dois membros ocultos: int seconds e int running (use 1 para em execução e 0 para parado). Implemente seu construtor para alocar a struct, inicializar seconds com o valor fornecido e definir running como 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! Basta imprimir uma mensagem confirmando a criação, depois liberar o temporizador e imprimir uma mensagem de limpeza.

Você receberá uma entrada: o número de segundos (um número inteiro) para inicializar o temporizador.

No 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 freed

A ideia principal 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 é definido apenas em timer.c. Isso é encapsulamento de verdade: os detalhes da implementação ficam completamente ocultos para quem usa 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: Imprima "Timer created"
    
    // TODO: Libere o timer
    
    // TODO: Imprima "Timer freed"
    
    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