![]() Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь КАТЕГОРИИ: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ТОП 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; просмотров: 150; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.138.117.118 (0.064 с.) |