Обзор проекта
Часть раздела Object Oriented Programming путешествия по C на Coddy — урок 44 из 61.
Задание
ЛегкоДавайте заложим основу для проекта Shape Drawer, создав базовую структуру Shape — интерфейс, который определяет, что может делать любая фигура, с помощью указателей на функции.
Вы создадите два файла для настройки этой полиморфной системы:
shape.h: Определите здесь основной интерфейс. Сначала создайте опережающее объявление (forward declaration) для структурыShape. Затем определите два типа указателей на функции:DrawFunc— принимает параметрconst Shape*и ничего не возвращаетAreaFunc— принимает параметрconst Shape*и возвращаетdouble
Shape, содержащую два указателя на функции:draw(типаDrawFunc) иarea(типаAreaFunc). Эта структура действует исключительно как интерфейс — она не содержит данных, специфичных для конкретной фигуры, только поведение.main.c: Продемонстрируйте работу вашего интерфейса, создав простую тестовую фигуру. Реализуйте две функции:test_draw— выводитDrawing test shapetest_area— возвращает42.0
Shape, привяжите его к этим тестовым функциям, а затем вызовите обе через интерфейс. Выведите результат площади с одним десятичным знаком.
Ваш вывод должен продемонстрировать, что указатели на функции работают правильно:
Drawing test shape
Area: 42.0Зачем нужно опережающее объявление? Вы можете задаться вопросом, почему typedef struct Shape Shape; появляется до того, как структура полностью определена. Это необходимо, потому что DrawFunc и AreaFunc ссылаются на const Shape* в своих типах параметров — но в этот момент в файле компилятор еще не видел полного определения структуры. Опережающее объявление говорит компилятору: "структура с именем Shape существует", чего достаточно для использования указателя на нее. Полное определение следует позже. Этот паттерн часто встречается в C, когда структуре нужно ссылаться на саму себя (напрямую или через указатели на функции).
Ключевая идея здесь заключается в том, что Shape ничего не знает о кругах или прямоугольниках — она знает только то, что любая фигура должна уметь отрисовывать (draw) себя и вычислять свою площадь (area). В следующих уроках вы создадите конкретные фигуры, которые будут включать эту базовую структуру и предоставлять свои собственные реализации. Не забудьте использовать include guards в заголовочном файле.
Попробуйте сами
#include <stdio.h>
#include "shape.h"
// TODO: Реализуйте функцию test_draw
// - Принимает параметр const Shape*
// - Выводит "Drawing test shape"
void test_draw(const Shape* shape) {
// TODO: Выведите требуемое сообщение
}
// TODO: Реализуйте функцию test_area
// - Принимает параметр const Shape*
// - Возвращает 42.0
double test_area(const Shape* shape) {
// TODO: Верните тестовое значение площади
}
int main() {
// TODO: Создайте экземпляр Shape
// TODO: Привяжите функции test_draw и test_area к фигуре
// TODO: Вызовите draw через интерфейс
// TODO: Вызовите area через интерфейс и выведите результат с одним знаком после запятой
// Формат: "Area: %.1f\n"
return 0;
}
Все уроки раздела Object Oriented Programming
1Основы модульного программирования
Заголовочные файлыСтражи включенияИсходные файлыСтатические функцииПовторение: Модульный калькулятор4Инкапсуляция
Концепция непрозрачных указателейОпределение непрозрачных структурГеттеры и сеттерыВалидация в сеттерахИтоги: Секретный ящик2Объекты и методы
Структуры как объектыУказатель 'Self'Константная корректностьУказатель против значенияВспомогательные методыИтоги: Point Manager5Проект: Простой банковский счет
Настройка проектаРеализация счета3Жизненный цикл объекта
Паттерн «Конструктор»Паттерн «Деструктор»Инициализация в стекеГлубокое копированиеПовторение: String Wrapper6Наследование через композицию
Встраивание структурПравило первого элементаДоступ к элементам родителяUpcastingПовторение: Иерархия фигур9Проект: Рисование фигур
Обзор проектаРеализация круга