Menu
Coddy logo textTech

Указатели на функции в структурах

Часть раздела Object Oriented Programming путешествия по C на Coddy — урок 38 из 61.

До сих пор мы использовали указатели на функции как отдельные переменные или передавали их в качестве аргументов. Следующим шагом к полиморфизму является встраивание указателя на функцию непосредственно внутрь структуры — это наделяет структуру собственным поведением.

Когда структура содержит указатель на функцию, каждый экземпляр может содержать свою функцию. Это означает, что два объекта одного и того же типа могут вести себя по-разному при вызове их указателя на функцию:

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

typedef struct {
    const char* name;
    PrintFunc print;  // Указатель на функцию как член структуры
} Printer;

Структура Printer теперь имеет два члена: данные (name) и поведение (print). Чтобы использовать её, вы назначаете функцию указателю во время инициализации:

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

int main() {
    Printer p;
    p.name = "Alert";
    p.print = loud_print;
    
    p.print("Hello");  // Вывод: !!! Hello !!!
    return 0;
}

Обратите внимание, как мы вызываем функцию через структуру: p.print("Hello"). Это очень похоже на вызов метода объекта в других языках. Структура содержит как свои данные, так и функцию, которая с ними работает.

Этот паттерн является основой полиморфизма в C — разным экземплярам могут быть назначены разные функции, что обеспечивает различное поведение для одного и того же типа struct.

challenge icon

Задание

Легко

Давайте создадим систему Notifier, которая демонстрирует, как структуры могут нести свое собственное поведение через указатели на функции.

Вы создадите два файла для организации вашего кода:

  • notifier.h: Определите тип указателя на функцию с именем NotifyFunc, который принимает параметр const char* и ничего не возвращает. Затем определите структуру Notifier, которая содержит name (типа const char*) и указатель на функцию notify типа NotifyFunc.
  • main.c: Подключите ваш заголовочный файл и реализуйте две функции уведомления:
    • alert_notify — выводит сообщение в формате: [ALERT] message
    • info_notify — выводит сообщение в формате: [INFO] message
    Затем создайте экземпляр Notifier, привяжите соответствующую функцию на основе входных данных и вызовите уведомление через указатель на функцию структуры.

Ваша программа получит два входных значения: тип уведомления (1 для alert, 2 для info) и сообщение для отображения.

В зависимости от типа, назначьте соответствующую функцию члену notify вашего уведомления, а затем вызовите её через структуру, чтобы отобразить сообщение.

Пример вывода, когда тип равен 1, а сообщение — "System starting":

[ALERT] System starting

Пример вывода, когда тип равен 2, а сообщение — "All systems normal":

[INFO] All systems normal

Не забудьте использовать include guards в вашем заголовочном файле и вызвать функцию через член структуры: n.notify(message)

Попробуйте сами

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

// TODO: Реализовать функцию alert_notify
// Должна выводить: [ALERT] message


// TODO: Реализовать функцию info_notify
// Должна выводить: [INFO] message


int main() {
    int type;
    char message[256];
    
    // Считать входные данные
    scanf("%d", &type);
    getchar(); // поглотить символ новой строки
    fgets(message, sizeof(message), stdin);
    
    // Удалить завершающий символ новой строки из message, если он есть
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: Создать экземпляр Notifier
    
    
    // TODO: В зависимости от type (1 для alert, 2 для info),
    // назначить соответствующую функцию члену notify структуры notifier
    
    
    // TODO: Вызвать уведомление через указатель на функцию в структуре
    // Использовать: n.notify(message)
    
    
    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming