Definición de structs opacos
Parte de la sección Programación Orientada a Objetos del Journey de C de Coddy. Lección 18 de 61.
Ahora que entiendes el concepto de los punteros opacos, veamos cómo completar el patrón. El encabezado declara que existe un tipo, pero el archivo fuente es donde defines qué hay realmente dentro.
Aquí tienes la configuración completa. Primero, el encabezado con solo la declaración anticipada:
// 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
Después, el archivo fuente contiene la definición real de la estructura:
// counter.c
#include "counter.h"
#include <stdlib.h>
struct Counter {
int value; // ¡Oculto desde fuera!
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);
}
El punto clave: struct Counter { ... } aparece únicamente en el archivo .c. Cualquier archivo que incluya counter.h sabe que Counter existe, pero no puede ver value ni step. Intentar escribir c->value en main.c provocaría un error del compilador: los miembros son verdaderamente invisibles.
Esta separación es la base de la encapsulación en C. El siguiente paso es proporcionar acceso controlado mediante funciones getter y setter.
Desafío
FácilConstruyamos un módulo Timer que demuestre el patrón de puntero opaco. Practicarás cómo ocultar la definición de la estructura dentro del archivo de código fuente, haciendo que sus miembros internos sean completamente invisibles para cualquier código que utilice tu módulo.
Crearás tres archivos:
timer.h: Esta es tu interfaz pública. Declara un tipo opacoTimerusando únicamente una declaración anticipada: ¡no incluyas aquí el cuerpo de la estructura! Declara también dos funciones:create_timer(recibe un entero que representa los segundos y devuelve un puntero a Timer) yfree_timer(recibe un puntero a Timer y realiza la limpieza). Usa protecciones de inclusión con el símboloTIMER_H.timer.c: Aquí vive el secreto. Define lastruct Timerreal con dos miembros ocultos:int secondsyint running(usa 1 para indicar que está en ejecución y 0 para indicar que está detenido). Implementa tu constructor para reservar memoria para la estructura, inicializarsecondscon el valor proporcionado y establecerrunningen 1. Implementa el destructor para liberar la memoria.main.c: Usa tu módulo Timer para crear un temporizador y confirmar que se creó correctamente. Como los miembros de la estructura están ocultos, no puedes acceder a ellos directamente. ¡Este es precisamente el objetivo! Simplemente imprime un mensaje que confirme la creación, después libera el temporizador e imprime un mensaje de limpieza.
Recibirás una entrada: el número de segundos (un entero) con el que se inicializará el temporizador.
En tu archivo principal, crea un temporizador con el valor de segundos proporcionado. Imprime un mensaje de creación, después libera el temporizador e imprime una confirmación.
Imprime la salida con este formato:
Timer created
Timer freedLa idea clave aquí es que main.c puede trabajar con punteros a Timer, pero no tiene forma de acceder directamente a seconds ni a running. Intentar escribir t->seconds en main.c provocaría un error del compilador, porque el cuerpo de la estructura solo está definido en timer.c. Esto es una encapsulación verdadera: los detalles de implementación están completamente ocultos para los usuarios de tu módulo.
Pruébalo tú mismo
#include <stdio.h>
#include "timer.h"
int main() {
int seconds;
scanf("%d", &seconds);
// TODO: Crea un temporizador con el valor de segundos proporcionado
// TODO: Print "Timer created"
// TODO: Libera el temporizador
// TODO: Imprime "Timer freed"
return 0;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de programación modular
Archivos de cabeceraGuardas de inclusiónArchivos fuenteFunciones estáticasRepaso: Calculadora modular4Encapsulamiento
Concepto de punteros opacosDefinición de structs opacosGetters y SettersValidación en settersResumen: Caja secreta7Punteros a funciones
Declaración de punteros a funcionesLlamada a punteros a funcionesTypedef para punteros a funcionesPasar funciones como argumentosRepaso: Dispatch de calculadora10Contenedores genéricos
Repaso de punteros voidWrapper genéricoSwap genéricoComparación genéricaRepaso: Array genérico2Objetos y métodos
Structs como objetosEl puntero 'Self'Const CorrectnessPuntero vs. ValorMétodos auxiliaresResumen: Point Manager5Proyecto: Cuenta bancaria simple
Configuración del proyectoImplementación de la cuenta3Ciclo de vida de los objetos
Patrón ConstructorPatrón DestructorInicialización en StackCopia profundaResumen: String Wrapper6Herencia mediante composición
Incrustación de StructsLa regla del primer miembroAcceso a miembros padreUpcastingResumen: Jerarquía de formas9Proyecto: Dibujador de figuras
Descripción general del proyectoImplementación del círculoImplementación del rectánguloUso polimórficoContenedor de figurasPractica por tu cuenta: Compilador de C online