Полиморфная итерация
Часть раздела Объектно-ориентированное программирование путешествия по C на Coddy. Урок 42 из 61.
Вы научились создавать интерфейсы и implement их с помощью различных конкретных functions. Настоящая польза проявляется, когда вы можете единообразно работать с коллекцией различных объектов: перебирать их и вызывать один и тот же function pointer для каждого из них, независимо от того, какое конкретное поведение подключено.
Представьте, что у вас есть массив структур Action, каждая из которых имеет назначенную ей функцию execute:
typedef void (*ExecuteFunc)(void);
typedef struct {
const char* name;
ExecuteFunc execute;
} Action;
void jump(void) { printf("Jumping!\n"); }
void run(void) { printf("Running!\n"); }
void rest(void) { printf("Resting...\n"); }Вы можете создать array из этих actions, each из которых связано с другой function, затем перебрать их с помощью простого цикла for:
int main() {
Action actions[3] = {
{ "Jump", jump },
{ "Run", run },
{ "Rest", rest }
};
for (int i = 0; i < 3; i++) {
printf("%s: ", actions[i].name);
actions[i].execute();
}
return 0;
}Цикл не знает и не заботится о том, что делает каждое действие внутри. Он просто вызывает execute() для каждого элемента.
Это полиморфизм в действии: один и тот же код обрабатывает объекты с совершенно разным поведением. Добавление нового типа действия не требует изменений в логике итерации; просто добавьте ещё один элемент в array.
Задание
ЛегкоДавайте создадим систему управления Task, демонстрирующую полиморфную итерацию: обработку коллекции объектов, которые имеют общий интерфейс, но выполняют разные действия.
Вы организуете код в трех файлах:
task.h: здесь Define интерфейс задачи. Create тип указателя на function с именемTaskFunc, который не принимает parameters и возвращает nothing. Затем Define structTask, содержащийname(типconst char*) и указатель на functionrunтипаTaskFunc.task.c: Implement три разные function задач, представляющие разные виды работы:backup_task: выводитBacking up data...cleanup_task: выводитCleaning up files...report_task: выводитGenerating report...
main.c: соберите здесь всё вместе. Create array из структурTask, каждую из которых свяжите с отдельной function задачи. Затем Iterate по array и Execute каждую задачу полиморфно: для каждой задачи выведите ее имя, а затем вызовите ее functionrun.
Ваша программа получит один входной параметр: число задач для выполнения (1, 2 или 3).
Create array, содержащий ровно три задачи в следующем order: backup task с именем Backup, cleanup task с именем Cleanup и report task с именем Report. В зависимости от входного значения count Iterate только по такому числу задач, начиная с начала array.
Для каждой задачи в ходе итерации выведите имя задачи, за которым следуют двоеточие и пробел, затем вызовите ее function run.
Пример вывода при входном значении 2:
Backup: Backing up data...
Cleanup: Cleaning up files...Пример вывода при входном значении 3:
Backup: Backing up data...
Cleanup: Cleaning up files...
Report: Generating report...Главная идея заключается в том, что вашему циклу не нужно знать, что делает каждая задача. Он просто выводит имя и вызывает run() для каждого элемента. Один и тот же код итерации единообразно обрабатывает все типы задач. Не забудьте использовать include guards в своем заголовочном файле.
Попробуйте сами
#include <stdio.h>
#include "task.h"
// Объявить функции задач, реализованные в task.c
void backup_task(void);
void cleanup_task(void);
void report_task(void);
int main() {
int count;
scanf("%d", &count);
// TODO: Создайте массив из 3 структур Task в следующем порядке:
// 1. Задача Backup с именем "Backup", использующая backup_task
// 2. Задача Cleanup с именем "Cleanup", использующая cleanup_task
// 3. Задача Report с именем "Report", использующая report_task
// TODO: Пройдите по 'count' задачам из массива
// Для каждой задачи выведите: "<name>: ", затем вызовите её функцию run
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы модульного программирования
Заголовочные файлыСтражи включенияИсходные файлыСтатические функцииПовторение: Модульный калькулятор4Инкапсуляция
Концепция непрозрачных указателейОпределение непрозрачных структурГеттеры и сеттерыВалидация в сеттерахИтоги: Секретный ящик2Объекты и методы
Структуры как объектыУказатель 'Self'Константная корректностьУказатель против значенияВспомогательные методыИтоги: Point Manager5Проект: Простой банковский счет
Настройка проектаРеализация счета8Полиморфизм
Указатели на функции в структурахСимуляция методовКонцепция интерфейсовРеализация интерфейсовПолиморфная итерацияПовторение: Greeter3Жизненный цикл объекта
Паттерн «Конструктор»Паттерн «Деструктор»Инициализация в стекеГлубокое копированиеПовторение: String Wrapper6Наследование через композицию
Встраивание структурПравило первого элементаДоступ к элементам родителяUpcastingПовторение: Иерархия фигур9Проект: Рисование фигур
Обзор проектаРеализация кругаРеализация прямоугольникаПолиморфное использованиеКонтейнер фигурПотренируйтесь самостоятельно: Онлайн-компилятор C