Menu
CoddyTech

Симуляция методов

Часть раздела Объектно-ориентированное программирование путешествия по 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 для каждого из них приводит к совершенно разным результатам. Структура хранит не только данные. Она хранит поведение, которое различается для каждого экземпляра.

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

challenge icon

Задание

Легко

Создадим систему 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;
}
quiz iconПроверьте себя

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

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

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