Patrón Constructor
Parte de la sección Object Oriented Programming del Journey de C de Coddy — lección 12 de 61.
En lenguajes como Java o C++, se crean objetos utilizando constructores: funciones especiales que reservan memoria e inicializan campos automáticamente. C no tiene tal característica, pero podemos simularla con un patrón sencillo: una función create_.
Una función constructora en C normalmente hace tres cosas: asigna memoria con malloc, inicializa todos los campos con los valores adecuados y devuelve un puntero al nuevo objeto:
typedef struct {
char *name;
int age;
} Person;
Person *create_person(const char *name, int age) {
Person *p = malloc(sizeof(Person));
p->name = malloc(strlen(name) + 1);
strcpy(p->name, name);
p->age = age;
return p;
}
La función devuelve un puntero porque el objeto reside en el heap, no en el stack. Esto significa que persiste después de que la función retorna y puede pasarse libremente. El llamador lo utiliza de esta manera:
Person *alice = create_person("Alice", 30);
printf("%s is %d years old\n", alice->name, alice->age);
Observe cómo el constructor maneja todos los detalles complicados: asignar el struct, asignar espacio para el string y copiar los datos. El llamador simplemente proporciona los valores iniciales y recibe un objeto listo para usar. Esto encapsula la lógica de creación en un solo lugar, haciendo que su código sea más limpio y menos propenso a errores.
Desafío
FácilVamos a construir un módulo Book que utilice el patrón de constructor para crear objetos de libro en el heap. Practicarás escribiendo una función create_ que maneje toda la asignación de memoria e inicialización, devolviendo un puntero listo para usar.
Crearás tres archivos:
book.h: Declara una estructuraBookcon dos miembros:char *title(un puntero a una cadena asignada dinámicamente) eint pages. También declara una función constructoracreate_bookque reciba una cadena de título y un conteo de páginas, y luego devuelva un puntero a un Book recién creado. Utiliza guardas de inclusión con el símboloBOOK_H.book.c: Implementa la funcióncreate_book. Tu constructor debe asignar memoria para la propia estructura Book, luego asignar memoria separada para la cadena del título (recuerda tener en cuenta el terminador nulo), copiar el título en la nueva memoria, establecer el campo de páginas y devolver el puntero al nuevo Book.main.c: Utiliza tu constructor para crear un libro y mostrar su información.
Recibirás dos entradas: el título del libro (una cadena) y el número de páginas (un entero).
En tu archivo principal, utiliza create_book para crear un nuevo libro con los valores proporcionados, luego imprime su información en este formato:
Title: {title}
Pages: {pages}Por ejemplo, con las entradas The C Programming Language y 272, la salida sería:
Title: The C Programming Language
Pages: 272Recuerda que tu constructor encapsula toda la lógica de creación: el llamador simplemente proporciona los valores iniciales y recibe un objeto completamente inicializado listo para usar.
Hoja de referencia
Una función constructora en C simula la creación de objetos asignando memoria e inicializando campos. Normalmente sigue el patrón de nomenclatura create_.
Una función constructora hace tres cosas:
- Asigna memoria con
malloc - Inicializa todos los campos con los valores adecuados
- Devuelve un puntero al nuevo objeto
Ejemplo de patrón de constructor:
typedef struct {
char *name;
int age;
} Person;
Person *create_person(const char *name, int age) {
Person *p = malloc(sizeof(Person));
p->name = malloc(strlen(name) + 1);
strcpy(p->name, name);
p->age = age;
return p;
}
Uso del constructor:
Person *alice = create_person("Alice", 30);
printf("%s is %d years old\n", alice->name, alice->age);
La función devuelve un puntero porque el objeto reside en el heap y persiste después de que la función retorna. Esto encapsula la lógica de creación en un solo lugar, haciendo que el código sea más limpio y menos propenso a errores.
Pruébalo tú mismo
#include <stdio.h>
#include <stdlib.h>
#include "book.h"
int main() {
char title[256];
int pages;
// Leer entrada
fgets(title, sizeof(title), stdin);
// Eliminar el salto de línea si está presente
for (int i = 0; title[i]; i++) {
if (title[i] == '\n') {
title[i] = '\0';
break;
}
}
scanf("%d", &pages);
// TODO: Use create_book para crear un nuevo libro con los valores proporcionados
// TODO: Imprimir la información del libro en el formato requerido:
// Title: {title}
// Pages: {pages}
// TODO: No olvide liberar la memoria asignada cuando termine
return 0;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
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írculo