Menu
Coddy logo textTech

Punteros a funciones en estructuras

Parte de la sección Object Oriented Programming del Journey de C de Coddy — lección 38 de 61.

Hasta ahora, hemos utilizado punteros a funciones como variables independientes o los hemos pasado como argumentos. El siguiente paso hacia el polimorfismo es incrustar un puntero a función directamente dentro de un struct, dándole al struct su propio comportamiento.

Cuando un struct contiene un puntero a función, cada instancia puede contener una función diferente. Esto significa que dos objetos del mismo tipo pueden comportarse de manera diferente cuando llamas a su puntero a función:

typedef void (*PrintFunc)(const char*);

typedef struct {
    const char* name;
    PrintFunc print;  // Puntero a función como miembro
} Printer;

La estructura Printer ahora tiene dos miembros: datos (name) y comportamiento (print). Para usarla, asignas una función al puntero durante la inicialización:

void loud_print(const char* msg) {
    printf("!!! %s !!!\n", msg);
}

int main() {
    Printer p;
    p.name = "Alert";
    p.print = loud_print;
    
    p.print("Hello");  // Salida: !!! Hello !!!
    return 0;
}

Observa cómo llamamos a la función a través del struct: p.print("Hello"). Esto se parece notablemente a llamar a un método en un objeto en otros lenguajes. El struct contiene tanto sus datos como la función que opera sobre ellos.

Este patrón es la base del polimorfismo en C: diferentes instancias pueden tener diferentes funciones asignadas, produciendo diferentes comportamientos a partir del mismo tipo struct.

challenge icon

Desafío

Fácil

Vamos a construir un sistema Notifier que demuestre cómo los structs pueden llevar su propio comportamiento a través de punteros a funciones.

Crearás dos archivos para organizar tu código:

  • notifier.h: Define un tipo de puntero a función llamado NotifyFunc que reciba un parámetro const char* y no devuelva nada. Luego, define un struct Notifier que contenga un name (un const char*) y un puntero a función notify de tipo NotifyFunc.
  • main.c: Incluye tu cabecera e implementa dos funciones de notificación:
    • alert_notify — imprime el mensaje en el formato: [ALERT] message
    • info_notify — imprime el mensaje en el formato: [INFO] message
    Luego, crea una instancia de Notifier, conecta la función apropiada basada en la entrada y llama a la notificación a través del puntero a función del struct.

Tu programa recibirá dos entradas: un tipo de notificación (1 para alert, 2 para info) y un mensaje para mostrar.

Basándote en el tipo, asigna la función correspondiente al miembro notify de tu notifier, luego llámala a través del struct para mostrar el mensaje.

Ejemplo de salida cuando el tipo es 1 y el mensaje es "System starting":

[ALERT] System starting

Ejemplo de salida cuando el tipo es 2 y el mensaje es "All systems normal":

[INFO] All systems normal

Recuerda usar guardas de inclusión en tu archivo de cabecera y llamar a la función a través del miembro del struct: n.notify(message)

Hoja de referencia

Los punteros a funciones pueden incrustarse directamente dentro de las estructuras, otorgando a cada instancia su propio comportamiento. Esta es una base para el polimorfismo en C.

Definición de una estructura con un puntero a función

Primero, defina un tipo de puntero a función y luego inclúyalo como miembro de la estructura:

typedef void (*PrintFunc)(const char*);

typedef struct {
    const char* name;
    PrintFunc print;  // Function pointer as a member
} Printer;

Uso de la estructura

Asigne una función al puntero durante la inicialización y luego llámela a través de la estructura:

void loud_print(const char* msg) {
    printf("!!! %s !!!\n", msg);
}

int main() {
    Printer p;
    p.name = "Alert";
    p.print = loud_print;
    
    p.print("Hello");  // Output: !!! Hello !!!
    return 0;
}

La sintaxis p.print("Hello") llama a la función a través de la estructura, de manera similar a llamar a un método en un objeto en otros lenguajes.

Comportamiento polimórfico

Diferentes instancias del mismo tipo de estructura pueden tener asignadas funciones diferentes, produciendo comportamientos distintos a partir del mismo tipo de estructura.

Pruébalo tú mismo

#include <stdio.h>
#include "notifier.h"

// TODO: Implementar la función alert_notify
// Debería imprimir: [ALERT] message


// TODO: Implementar la función info_notify
// Debería imprimir: [INFO] message


int main() {
    int type;
    char message[256];
    
    // Leer entrada
    scanf("%d", &type);
    getchar(); // consumir nueva línea
    fgets(message, sizeof(message), stdin);
    
    // Eliminar el salto de línea final del mensaje si está presente
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: Crear una instancia de Notifier
    
    
    // TODO: Basado en el tipo (1 para alerta, 2 para información),
    // asignar la función apropiada al miembro notify del notifier
    
    
    // TODO: Llamar a la notificación a través del puntero de función de la estructura
    // Usar: n.notify(message)
    
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Object Oriented Programming