Menu
Coddy logo textTech

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

Часть раздела Объектно-ориентированное программирование путешествия по C на Coddy. Урок 38 из 61.

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

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

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

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

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

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;
}

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

Этот шаблон является основой полиморфизма в C: разные instance могут иметь разные function, назначенные им, создавая разное поведение для одного и того же типа структуры.

challenge icon

Задание

Легко

Создадим систему Notifier, демонстрирующую, как структуры могут содержать собственное поведение с помощью указателей на function.

Ты создашь два файла, чтобы организовать свой код:

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

Твоя программа получит два входных значения: тип notification (1 для alert, 2 для info) и message, который нужно отобразить.

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

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

[ALERT] System starting

Пример вывода, когда тип равен 2, а message — "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Проверьте себя

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

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C