Wrapper genérico
Parte de la sección Programación Orientada a Objetos del Journey de C de Coddy. Lección 50 de 61.
Un void* por sí solo puede almacenar cualquier dato, pero tiene un defecto crítico: pierdes la pista de qué tipo contiene. Para crear contenedores genéricos realmente útiles, debemos combinar el puntero a los datos con información de tipo. Aquí es donde entra en juego el patrón Generic Wrapper.
La idea es simple: crea una estructura que agrupe un void* con un enumerado que identifique el tipo almacenado. De este modo, el envoltorio siempre sabe cómo interpretar su contenido.
typedef enum {
TYPE_INT,
TYPE_STRING
} DataType;
typedef struct {
void* data;
DataType type;
} Wrapper;Al almacenar datos, asignas memoria para el valor real y registras su tipo. Al recuperarlos, compruebas el tipo antes de convertirlo:
Wrapper wrap_int(int value) {
int* p = malloc(sizeof(int));
*p = value;
return (Wrapper){ .data = p, .type = TYPE_INT };
}
void print_wrapper(Wrapper* w) {
if (w->type == TYPE_INT) {
printf("%d\n", *(int*)w->data);
} else if (w->type == TYPE_STRING) {
printf("%s\n", (char*)w->data);
}
}Este patrón es la base para crear contenedores genéricos con seguridad de tipos en C. El enum actúa como una etiqueta de tipo en tiempo de ejecución, lo que permite que tu código tome decisiones seguras sobre cómo manejar los datos almacenados.
Desafío
FácilConstruyamos un sistema genérico de envoltorios con seguridad de tipos que pueda almacenar un entero o una cadena, realizando un seguimiento del tipo que contiene para que podamos recuperar e imprimir los datos de forma segura más adelante.
Organizarás tu código en tres archivos:
wrapper.h: Define un enumDataTypecon los valoresTYPE_INTyTYPE_STRING. Después, define una estructuraWrapperque agrupe un puntero de datosvoid*con un campoDataType. Declara los prototipos de las funciones para crear envoltorios e imprimir su contenido.wrapper.c: Implementa la funcionalidad del envoltorio:wrap_int: recibe un entero, reserva memoria para él, almacena el valor y devuelve un Wrapper con la etiqueta de tipo correspondientewrap_string: recibe una cadena (char*), reserva memoria y copia la cadena, y devuelve un Wrapper con la etiqueta de tipo de cadenaprint_wrapper: comprueba la etiqueta de tipo e imprime los datos adecuadamente (el entero tal cual, la cadena tal cual)free_wrapper: libera los datos reservados dinámicamente dentro del envoltorio
main.c: Une todo. Lee un indicador de tipo (ipara un entero,spara una cadena), seguido del valor. Crea el envoltorio correspondiente, imprime su contenido y libera la memoria.
Tu programa recibirá dos entradas:
- Un indicador de tipo:
ipara un entero ospara una cadena - El valor que se envolverá
Salida de ejemplo cuando las entradas son i y 42:
42Salida de ejemplo cuando las entradas son s y Hello:
HelloSalida de ejemplo cuando las entradas son i y -100:
-100Salida de ejemplo cuando las entradas son s y Generic Programming:
Generic ProgrammingRecuerda usar protectores de inclusión en tu archivo de encabezado. Para copiar cadenas, reserva suficiente espacio para la cadena más el terminador nulo usando strlen y strcpy.
Pruébalo tú mismo
#include <stdio.h>
#include <string.h>
#include "wrapper.h"
int main() {
char type;
scanf("%c", &type);
getchar(); // consumir el salto de línea
Wrapper w;
if (type == 'i') {
int value;
scanf("%d", &value);
// TODO: Crear un wrapper de entero usando wrap_int
} else if (type == 's') {
char str[256];
fgets(str, sizeof(str), stdin);
// Eliminar el salto de línea final si está presente
str[strcspn(str, "\n")] = '\0';
// TODO: Crear un wrapper de cadena usando wrap_string
}
// TODO: Imprimir el contenido del wrapper usando print_wrapper
// TODO: Liberar la memoria del wrapper usando free_wrapper
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