Указатели на функции в структурах
Часть раздела Объектно-ориентированное программирование путешествия по 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, назначенные им, создавая разное поведение для одного и того же типа структуры.
Задание
ЛегкоСоздадим систему Notifier, демонстрирующую, как структуры могут содержать собственное поведение с помощью указателей на function.
Ты создашь два файла, чтобы организовать свой код:
notifier.h: Определи тип указателя наfunctionпод названиемNotifyFunc, который принимаетconst char*parameterи ничего не возвращает. Затем определи структуруNotifier, содержащуюname(значение типаconst char*) и указатель наfunctionnotifyтипаNotifyFunc.main.c: Подключи свой заголовочный файл и реализуй две функции уведомлений:alert_notify: выводит сообщение в формате:[ALERT] messageinfo_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;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы модульного программирования
Заголовочные файлыСтражи включенияИсходные файлыСтатические функцииПовторение: Модульный калькулятор4Инкапсуляция
Концепция непрозрачных указателейОпределение непрозрачных структурГеттеры и сеттерыВалидация в сеттерахИтоги: Секретный ящик2Объекты и методы
Структуры как объектыУказатель 'Self'Константная корректностьУказатель против значенияВспомогательные методыИтоги: Point Manager5Проект: Простой банковский счет
Настройка проектаРеализация счета8Полиморфизм
Указатели на функции в структурахСимуляция методовКонцепция интерфейсовРеализация интерфейсовПолиморфная итерацияПовторение: Greeter3Жизненный цикл объекта
Паттерн «Конструктор»Паттерн «Деструктор»Инициализация в стекеГлубокое копированиеПовторение: String Wrapper6Наследование через композицию
Встраивание структурПравило первого элементаДоступ к элементам родителяUpcastingПовторение: Иерархия фигур9Проект: Рисование фигур
Обзор проектаРеализация кругаРеализация прямоугольникаПолиморфное использованиеКонтейнер фигурПотренируйтесь самостоятельно: Онлайн-компилятор C