Punteros a funciones en estructuras
Parte de la sección Programación Orientada a Objetos del Journey de C de Coddy. Lección 38 de 61.
Hasta ahora, hemos usado punteros de function como variables independientes o los hemos pasado como argumentos. El siguiente paso hacia el polimorfismo es insertar un puntero de function directamente dentro de una estructura, dotando a la estructura de su propio comportamiento.
Cuando una estructura 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 pointer 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 de la estructura: p.print("Hello"). Esto se parece notablemente a llamar a un método en un objeto en otros lenguajes. La estructura contiene tanto sus datos como la función que opera sobre ellos.
Este patrón es la base del polimorfismo en C: distintas instancias pueden tener diferentes funciones asignadas, lo que produce comportamientos diferentes a partir del mismo tipo de estructura.
Desafío
FácilConstruyamos un sistema Notifier que demuestre cómo las estructuras pueden llevar su propio comportamiento mediante punteros a funciones.
Crearás dos archivos para organizar tu código:
notifier.h: Define un tipo de puntero a función llamadoNotifyFuncque recibe un parámetroconst char*y no devuelve nada. Después, define una estructuraNotifierque contenga unname(unconst char*) y un puntero a funciónnotifyde tipoNotifyFunc.main.c: Incluye tu archivo de encabezado e implementa dos funciones de notificación:alert_notify: imprime el mensaje con el formato:[ALERT] messageinfo_notify: imprime el mensaje con el formato:[INFO] message
Notifier, asígnale la función adecuada según la entrada y llama a la notificación mediante el puntero a función de la estructura.
Tu programa recibirá dos entradas: un tipo de notificación (1 para alerta, 2 para información) y un mensaje que mostrar.
Según el tipo, asigna la función correspondiente al miembro notify de tu notificador y después llámala a través de la estructura para mostrar el mensaje.
Salida de ejemplo cuando el tipo es 1 y el mensaje es "System starting":
[ALERT] System startingSalida de ejemplo cuando el tipo es 2 y el mensaje es "All systems normal":
[INFO] All systems normalRecuerda usar protectores de inclusión en tu archivo de encabezado y llamar a la función mediante el miembro de la estructura: n.notify(message)
Pruébalo tú mismo
#include <stdio.h>
#include "notifier.h"
// TODO: Implementa la función alert_notify
// Debe imprimir: [ALERT] message
// TODO: Implementa la función info_notify
// Debe imprimir: [INFO] message
int main() {
int type;
char message[256];
// Leer la entrada
scanf("%d", &type);
getchar(); // consumir el salto de 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: Crea una instancia de Notifier
// TODO: Basado en type (1 para alert, 2 para info),
// asigna la función apropiada al miembro notify del notifier
// TODO: Llama a la notificación a través del puntero a función de la struct
// Usa: n.notify(message)
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 cuenta8Polimorfismo
Punteros a funciones en estructurasSimulando métodosEl concepto de interfazImplementando interfacesIteración polimórficaResumen: Greeter3Ciclo 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