Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Недетерминированная множественность композиции
До сих пор был рассмотрен лишь случай, когда множественная композиция имела конечную детерминированную кратность. В частности, в примере о многоугольнике (Polygon) количество дочерних объектов в явном виде передавалось родительскому объекту-агрегату в конструкторе. Это число использовалось для выделения памяти массива дочерних объектов. Разумеется, массив всегда имеет конечный фиксированный размер. Изменить размер массива дочерних объектов в течение жизни объекта-агрегата было нельзя.
На практике при моделировании реальных иерархий взаимодействующих объектов из естественных предметных областей довольно редко встречаются случаи, когда число связей при множественной композиции является заранее известным и неизменным. Гораздо чаще встречаются ситуации, когда количество дочерних объектов варьируется от 0 до бесконечности, а состав связей динамически изменяется за время жизни объекта-агрегата.
Предположим, местоположение вертолета в пространстве в течение вылета протоколируется с некоторой периодичностью, и затем путь подвергается той или иной форме обработки. Пусть для целей протоколирования используется следующий класс:
flightjournal.hpp
#ifndef _FLIGHTJOURNAL_HPP_ #define _FLIGHTJOURNAL_HPP_
//************************************************************************
#include "point3d.hpp"
//************************************************************************
class Helicopter;
//************************************************************************
// Класс, представляющий журнал полета вертолета class FlightJournal {
/*-----------------------------------------------------------------*/
public:
/*-----------------------------------------------------------------*/
// Конструктор с аргументами: // - ссылка на связанный объект вертолет // - максимальное количество фиксируемых точек FlightJournal ( const Helicopter & _helicopter , int _nMaxLocations );
// Удаленный конструктор копий и оператор присвоения FlightJournal (const FlightJournal &) = delete; FlightJournal & operator = (const FlightJournal &) = delete;
// Деструктор ~FlightJournal ();
// Метод доступа к связанному с журналом вертолету const Helicopter & getHelicopter () const;
// Метод для извлечения максимального количества точек для фиксации int getMaxPositionsCount () const;
// Метод для извлечения количества уже зафиксированных точек int getPositionsCount () const;
// Метод для извлечения координат конкретной зафиксированной точки
Point3D getPosition (int _index) const;
// Метод фиксации текущего местоположения вертолета void trackPosition ();
// Метод вычисления длины пути вертолета в полете double totalDistance () const;
/*-----------------------------------------------------------------*/
private:
/*-----------------------------------------------------------------*/
// Ссылка на объект-вертолет const Helicopter & m_helicopter;
// Количество и массив данных точек местоположения const int m_nMaxPositions; Point3D * m_pPositions;
// Количество уже заполненных точек местоположения int m_nUsedPositions;
/*-----------------------------------------------------------------*/
};
//************************************************************************
// Метод доступа к связанному с журналом вертолету inline const Helicopter & FlightJournal::getHelicopter () const { return m_helicopter; }
//************************************************************************
// Метод для извлечения максимального количества точек для фиксации Inline int FlightJournal::getMaxPositionsCount () const { return m_nMaxPositions; }
//************************************************************************
// Метод для извлечения количества уже зафиксированных точек Inline int FlightJournal::getPositionsCount () const { return m_nUsedPositions; }
//************************************************************************
#endif // _FLIGHTJOURNAL_HPP_
flightjournal.cpp
#include "flightjournal.hpp" #include "helicopter.hpp"
#include <stdexcept>
//************************************************************************
// Конструктор с аргументами FlightJournal::FlightJournal ( const Helicopter & _helicopter, int _nMaxPositions ) : m_helicopter(_helicopter) , m_nMaxPositions(_nMaxPositions) , m_nUsedPositions(0) // <- Изначально нет данных о местоположении { // Инвариант: максимальное число позиций должно быть положительным if (m_nMaxPositions < 1) throw std::logic_error("Number of positions must be positive");
// Выделяем массив фиксированного размера для хранения координат позиций m_pPositions = new Point3D[ m_nMaxPositions ]; }
//************************************************************************
// Деструктор FlightJournal::~FlightJournal () { // Освобождаем массив координат delete[] m_pPositions; }
//************************************************************************
// Метод для извлечения координат конкретной зафиксированной точки Point3D FlightJournal::getPosition (int _index) const { // Проверяем корректность индекса точки if (_index >= 0 && _index < m_nUsedPositions) // Возвращаем координаты этой точки
return m_pPositions[ _index ];
Else // Исключение: индекс позиции за допустимыми пределами throw std::logic_error("Position index is out of range"); }
//************************************************************************
// Метод фиксации текущего местоположения вертолета void FlightJournal::trackPosition () { // Проверяем наличие свободного места в массиве для очередной точки if (m_nUsedPositions == m_nMaxPositions) // Исключение: выделенная в конструкторе память исчерпана throw std::logic_error("No space left in the journal");
// Извлекаем текущие координаты вертолета и запоминаем его местоположение Point3D currentPosition = m_helicopter.getCurrentPosition(); m_pPositions[ m_nUsedPositions++ ] = currentPosition; }
//************************************************************************
// Метод вычисления длины пути вертолета в полете double FlightJournal::totalDistance () const { double result = 0.0; for (int i = 0; i < m_nUsedPositions - 1; i++) result += m_pPositions[ i ].distanceTo(m_pPositions[ i + 1 ]); return result; }
//************************************************************************
Структура объекта-журнала, инициализированного с максимальным количеством точек, равным 4, в памяти выглядит приблизительно следующим образом:
Основной проблемой данного решения является невозможность изменения количества фиксируемых местоположений вертолета. В этой задаче, как и в большинстве реальных задач, маловероятно, что конкретное число местоположений будет известно заранее. Это прекрасный случай применения ранее изученного STL-контейнера std::vector. Перепишем пример с журналом полета вертолета с применением вектора для хранения координат вертолета. Поскольку вектор полностью берет на себя задачу управления внутренним массивом данных с координатами в зафиксированных точках, реализация такого отношения существенно упрощается:
flightjournal_v2.hpp
#ifndef _FLIGHTHJOURNAL_V2_HPP_ #define _FLIGHTHJOURNAL_V2_HPP_
//************************************************************************
#include "point3d.hpp" #include <vector>
//************************************************************************
class Helicopter;
//************************************************************************
// Класс, представляющий журнал полета вертолета class FlightJournal {
/*-----------------------------------------------------------------*/
public:
/*-----------------------------------------------------------------*/
// Конструктор с только одним аргументом: ссылка на связанный объект-вертолет // Больше не нужно передавать максимальное количество позиций! FlightJournal (const Helicopter & _helicopter);
// Исчезает необходимость в запрещении конструктора копий и оператора присвоения // Деструктор тоже не нужен!
// Метод доступа к связанному с журналом вертолету const Helicopter & getHelicopter () const;
// Не нужен и метод, возвращающий максимальное количество позиций!
// Метод для извлечения количества уже зафиксированных точек int getPositionsCount () const;
// Метод для извлечения координат конкретной зафиксированной точки Point3D getPosition (int _index) const;
// Метод фиксации текущего местоположения вертолета void trackPosition ();
// Метод вычисления длины пути вертолета в полете double totalDistance () const;
/*-----------------------------------------------------------------*/
private:
/*-----------------------------------------------------------------*/
// Ссылка на объект-вертолет const Helicopter & m_helicopter;
// Вектор зафиксированных точек std::vector< Point3D > m_positions;
/*-----------------------------------------------------------------*/
};
//************************************************************************
// Метод доступа к связанному с журналом вертолету
inline const Helicopter & FlightJournal::getHelicopter () const { return m_helicopter; }
//************************************************************************
// Метод для извлечения количества уже зафиксированных точек Inline int FlightJournal::getPositionsCount () const { return m_positions.size(); }
//************************************************************************
#endif // _FLIGHTHJOURNAL_V2_HPP_
flightjournal_v2.cpp
#include "flightjournal_v2.hpp" #include "helicopter.hpp"
//************************************************************************
// Конструктор с аргументами FlightJournal::FlightJournal (const Helicopter & _helicopter) : m_helicopter(_helicopter) // Конструктор вектора вызовется автоматически { // Никаких инвариантов проверять не нужно }
//************************************************************************
// Метод для извлечения координат конкретной зафиксированной точки Point3D FlightJournal::getPosition (int _index) const { // Проверку индекса осуществляет сам вектор return m_positions.at(_index); }
//************************************************************************
void FlightJournal::trackPosition () { // Больше нет ограничений на количество точек. // Просто извлекаем текущие координаты вектора и кладем их в вектор Point3D currentPosition = m_helicopter.getCurrentPosition(); m_positions.push_back(currentPosition); }
//************************************************************************
// Метод вычисления длины пути вертолета в полете double FlightJournal::totalDistance () const { double result = 0.0; for (int i = 0; i < m_positions.size() - 1; i++) result += m_positions[ i ].distanceTo(m_positions[ i + 1 ]); return result; }
//************************************************************************
Новая структура выглядит в памяти следующим образом:
Разумеется, внутри объекта-вектора в той или иной форме хранится адрес блока данных с объектами Point3D в динамической памяти, количество используемых и выделенных элементов (чаще вместо хранения количества как числа, реализация стандартной библиотеки хранит адреса элементов, следующих в блоке данных за последним заполненным элементом и последним выделенным).
Помимо того, что такая реализация предоставляет решение основной проблемы - динамическое изменение количества фиксируемых позиций вертолета - благодаря использованию вектора удается достичь существенных упрощений реализации: ● нет необходимости в передаче и извлечении максимального числа точек; ● исчезает необходимость в явном деструкторе, поскольку деструктор вектора, который освободит выделенный блок памяти, будет автоматически вызван из генерируемого компилятором автоматического деструктора класса FlightJournal; ● исчезает необходимость в запрещении копирования, поскольку реализация класса std::vector обладает функциональностью корректного копирования своего содержимого, и никаких "висячих" указателей в автоматическом конструкторе копий не возникнет;
● вектору также можно доверить проверку индексов при доступе к конкретным точкам.
|
||||||||
Последнее изменение этой страницы: 2017-02-17; просмотров: 144; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.15.235.196 (0.065 с.) |