Menu
Coddy logo textTech

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.

challenge icon

Desafio

Fácil

Vamos 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 tipo Timer opaco 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) e free_timer (recebe um ponteiro para Timer e faz a limpeza). Use guardas de inclusão com o símbolo TIMER_H.
  • timer.c: É aqui que o segredo vive. 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! 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 freed

A 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;
}
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