Симуляция методов
Часть раздела Объектно-ориентированное программирование путешествия по C на Coddy. Урок 39 из 61.
Вы уже видели, как поместить указатель на функцию в структуру. Настоящая сила проявляется, когда вы назначаете разные функции разным экземплярам одного и того же типа структуры. Так мы имитируем методы с различным поведением.
Рассмотрим структуру, которая представляет действие с настраиваемой логикой:
typedef void (*ActionFunc)(void);
typedef struct {
const char* name;
ActionFunc execute;
} Action;При создании экземпляров вы связываете с каждым из них разные функции:
void say_hello(void) {
printf("Hello!\n");
}
void say_goodbye(void) {
printf("Goodbye!\n");
}
int main() {
Action greet = { "Greet", say_hello };
Action farewell = { "Farewell", say_goodbye };
greet.execute(); // Вывод: Hello!
farewell.execute(); // Вывод: Goodbye!
return 0;
}И greet, и farewell имеют один и тот же тип (Action), но вызов execute для каждого из них приводит к совершенно разным результатам. Структура хранит не только данные. Она хранит поведение, которое различается для каждого экземпляра.
Этот шаблон отражает принцип работы объектов в других языках: у каждого объекта может быть своя реализация метода, даже если они используют один и тот же интерфейс.
Задание
ЛегкоСоздадим систему Speaker, которая показывает, как экземпляры одного и того же типа структуры могут вести себя совершенно по-разному в зависимости от того, какая функция им назначена.
Для организации кода ты создашь два файла:
speaker.h: Определи тип указателя на функцию с именемSpeakFunc, которая не принимает параметров и ничего не возвращает. Затем определи структуруSpeaker, содержащуюname(типconst char*) и указатель на функциюspeakтипаSpeakFunc.main.c: Подключи заголовочный файл и реализуй три разные функции, озвучивающие звуки:bark: выводитWoof!meow: выводитMeow!chirp: выводитChirp!
Speaker, назначь каждому из них свою функцию в зависимости от ввода и вызови их методыspeak, чтобы увидеть полиморфное поведение в действии.
Программа получит два входных значения: тип первого говорящего (1 для bark, 2 для meow, 3 для chirp) и тип второго говорящего (также 1, 2 или 3).
Создай два экземпляра Speaker. Можешь назвать их как угодно (например, "Dog", "Cat", "Bird" или просто "Speaker1", "Speaker2"). Назначь каждому экземпляру подходящую функцию в соответствии с его входным кодом, затем вызови speak для каждого экземпляра по порядку.
Пример вывода, когда первый тип равен 1, а второй тип равен 2:
Woof!
Meow!Пример вывода, когда первый тип равен 3, а второй тип равен 3:
Chirp!
Chirp!Главная идея здесь в том, что оба говорящих имеют один и тот же тип Speaker, но выводят разные результаты, поскольку каждому из них назначена своя функция для члена speak. Не забудь использовать защиту от повторного включения в заголовочном файле.
Попробуйте сами
#include <stdio.h>
#include "speaker.h"
// TODO: Реализуйте функцию bark, которая выводит "Woof!"
// TODO: Реализуйте функцию meow, которая выводит "Meow!"
// TODO: Реализуйте функцию chirp, которая выводит "Chirp!"
int main() {
int type1, type2;
scanf("%d", &type1);
scanf("%d", &type2);
// TODO: Создайте два экземпляра Speaker
// TODO: Назначьте функцию speak первого экземпляра Speaker в зависимости от type1
// (1 = bark, 2 = meow, 3 = chirp)
// TODO: Назначьте функцию speak второго экземпляра Speaker в зависимости от type2
// (1 = bark, 2 = meow, 3 = chirp)
// TODO: Вызовите speak для каждого экземпляра Speaker по порядку
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы модульного программирования
Заголовочные файлыСтражи включенияИсходные файлыСтатические функцииПовторение: Модульный калькулятор4Инкапсуляция
Концепция непрозрачных указателейОпределение непрозрачных структурГеттеры и сеттерыВалидация в сеттерахИтоги: Секретный ящик2Объекты и методы
Структуры как объектыУказатель 'Self'Константная корректностьУказатель против значенияВспомогательные методыИтоги: Point Manager5Проект: Простой банковский счет
Настройка проектаРеализация счета8Полиморфизм
Указатели на функции в структурахСимуляция методовКонцепция интерфейсовРеализация интерфейсовПолиморфная итерацияПовторение: Greeter3Жизненный цикл объекта
Паттерн «Конструктор»Паттерн «Деструктор»Инициализация в стекеГлубокое копированиеПовторение: String Wrapper6Наследование через композицию
Встраивание структурПравило первого элементаДоступ к элементам родителяUpcastingПовторение: Иерархия фигур9Проект: Рисование фигур
Обзор проектаРеализация кругаРеализация прямоугольникаПолиморфное использованиеКонтейнер фигурПотренируйтесь самостоятельно: Онлайн-компилятор C