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 noción del tipo que contiene. Para construir contenedores genéricos realmente útiles, necesitamos asociar el puntero a los datos con información de tipo. Aquí es donde entra en juego el patrón de envoltorio genérico.
La idea es simple: crear un struct que agrupe un void* con un enum que identifique el tipo almacenado. De esta manera, el envoltorio siempre sabe cómo interpretar sus contents.
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 realizar la conversión:
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 de wrappers genérico y seguro respecto a los tipos que pueda almacenar un integer o un string, manteniendo un registro del tipo que contiene para que podamos recuperar e imprimir los data de forma segura más adelante.
Organizarás tu código en tres archivos:
wrapper.h: Define unDataTypeenum con los valoresTYPE_INTyTYPE_STRING. Después define una estructuraWrapperque agrupe unvoid*data pointer con unDataTypefield. Declara los function prototypes para crear wrappers e imprimir sus contents.wrapper.c: Implementa la funcionalidad del wrapper:wrap_int: recibe un integer, asigna memory para él, almacena el valor y devuelve un Wrapper con la etiqueta de tipo apropiadawrap_string: recibe un string (char*), asigna memory y copia el string, y devuelve un Wrapper con la etiqueta de tipo stringprint_wrapper: comprueba la etiqueta de tipo e imprime los data de forma apropiada (integer tal cual, string tal cual)free_wrapper: libera los data asignados dinámicamente dentro del wrapper
main.c: Reúne todo. Lee un indicador de tipo (ipara integer,spara string) seguido del valor. Crea el wrapper apropiado, imprime sus contents y libera la memory.
Tu programa recibirá dos entradas:
- Un indicador de tipo:
ipara integer ospara string - 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 include guards en tu archivo de encabezado. Para copiar strings, asigna suficiente espacio para el string más el terminador null 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