Контейнер фигур
Часть раздела Объектно-ориентированное программирование путешествия по C на Coddy. Урок 48 из 61.
Задание
ЛегкоДавайте доведём проект Shape Drawer до грандиозного финала! Вы создадите контейнер фигур, содержащий смешанную коллекцию Circle и Rectangle, а затем переберёте их, чтобы вычислить общую площадь, продемонстрировав истинную силу полиморфизма.
Основываясь на всём, что вы уже создали, ваш полный проект будет включать:
shape.hиshape.c: ваш базовый интерфейс Shape и функцияprocess_shape.circle.hиcircle.c: ваша реализация Circle с её конструктором и вычислением площади.rectangle.hиrectangle.c: ваша реализация Rectangle с её конструктором и вычислением площади.main.c: именно здесь происходит волшебство. Вы создадите массив указателейShape*, способный содержать фигуры любого типа. Заполните его смесью Circle и Rectangle, а затем пройдите по массиву, чтобы вычислить и вывести общую площадь всех фигур.
Ваша программа получит следующие входные данные:
- Количество создаваемых фигур
- Для каждой фигуры: индикатор типа (
cдля круга,rдля прямоугольника), за которым следуют её размеры
Для каждой фигуры в вашем контейнере самостоятельно вызовите draw и area через указатель Shape* (shapes[i]->draw(shapes[i]), shapes[i]->area(shapes[i])) и добавьте площадь к текущей общей сумме. Здесь не используйте process_shape из shape.c: она выводит дополнительную строку Area: для каждой фигуры, которой нет в ожидаемом выводе. После обработки всех фигур выведите общую площадь с 2 знаками после запятой в формате Total Area: X.XX.
Пример с входными данными 3, затем c 5.0, r 4.0 3.0, c 2.0:
Drawing Circle with radius: 5.00
Drawing Rectangle with width: 4.00 and height: 3.00
Drawing Circle with radius: 2.00
Total Area: 103.11Пример с входными данными 2, затем r 6.0 4.0, r 3.0 2.0:
Drawing Rectangle with width: 6.00 and height: 4.00
Drawing Rectangle with width: 3.00 and height: 2.00
Total Area: 30.00Ключевая идея заключается в том, что ваш массив хранит указатели Shape*. Ему не важно, является ли каждый элемент Circle или Rectangle. Когда вы перебираете массив и вызываете draw и area через каждый указатель, автоматически выполняется правильная реализация — в зависимости от того, как была создана каждая фигура. Это полиморфизм в действии: один цикл, один интерфейс, несколько вариантов поведения.
Помните, что вам нужно хранить в массиве указатели на встроенные члены Shape ваших конкретных фигур. Используйте 3.14159 для π при вычислении площади круга.
Важно: чтение символа типа фигуры: после чтения количества фигур с помощью scanf("%d", &n) каждый последующий вызов для чтения символа типа должен пропускать оставшийся символ новой строки во входном буфере. Для этого используйте ведущий пробел в строке формата:
scanf(" %c", &type); // note the space before %cБез ведущего пробела scanf прочитает символ новой строки, оставшийся от предыдущего ввода, вместо ожидаемого c или r, из-за чего проверка типа фигуры незаметно завершится неудачей и не выведет ничего.
Попробуйте сами
#include <stdio.h>
#include <stdlib.h>
#include "shape.h"
#include "circle.h"
#include "rectangle.h"
int main() {
// TODO: Прочитать количество фигур
// TODO: Выделить массивы для circles, rectangles и указателей Shape*
// TODO: Пройти циклом по каждой фигуре, прочитать её тип и размеры,
// создать фигуру и сохранить указатель на её базу в массив shapes
// TODO: Пройти циклом по массиву shapes, вызвать shapes[i]->draw(...) и
// shapes[i]->area(...) напрямую и накопить общую площадь
// (не вызывайте process_shape: он печатает лишнюю строку Area)
// TODO: Вывести общую площадь в формате: Total Area: X.XX
// TODO: Освободить выделенную память
return 0;
}
Все уроки раздела Объектно-ориентированное программирование
1Основы модульного программирования
Заголовочные файлыСтражи включенияИсходные файлыСтатические функцииПовторение: Модульный калькулятор4Инкапсуляция
Концепция непрозрачных указателейОпределение непрозрачных структурГеттеры и сеттерыВалидация в сеттерахИтоги: Секретный ящик2Объекты и методы
Структуры как объектыУказатель 'Self'Константная корректностьУказатель против значенияВспомогательные методыИтоги: Point Manager5Проект: Простой банковский счет
Настройка проектаРеализация счета3Жизненный цикл объекта
Паттерн «Конструктор»Паттерн «Деструктор»Инициализация в стекеГлубокое копированиеПовторение: String Wrapper6Наследование через композицию
Встраивание структурПравило первого элементаДоступ к элементам родителяUpcastingПовторение: Иерархия фигур9Проект: Рисование фигур
Обзор проектаРеализация кругаРеализация прямоугольникаПолиморфное использованиеКонтейнер фигурПотренируйтесь самостоятельно: Онлайн-компилятор C