- •Ооп: Лекция 9. Композиция объектов.
- •Композиция объектов
- •Простейшая композиция по значению
- •Множественная композиция по значению
- •Ссылочная композиция — логическое объединение
- •Композиция с разрываемой связью
- •Разрываемая ссылочная композиция
- •Недетерминированная множественность композиции
- •Множественная композиция объектов-сущностей
- •Полные примеры из лекции
Разрываемая ссылочная композиция
Ссылочные связи между объектами также не обязательно являются постоянными и могут изменяться в течение жизни объектов. Аналогично предыдущему примеру, такое отношение моделируют при помощи указателя на дочерний объект. Однако в данном случае объект-родитель не является ответственным за уничтожение дочернего объекта.
Ниже приведен пример класса, моделирующего вертолетную площадку (HelicopterPad). Площадка может принимать только один приземлившийся вертолет (Helicopter). Объект-вертолет может приземляться на площадку через вызов метода land, а затем покидать ее после вызова unland. Площадка должна проверять, что на ней может быть приземлен единственный вертолет, и что взлет возможен только, если вертолет до этого приземлился.
При этом уничтожение вертолета никогда не является задачей вертолетной площадки. В данном случае пропадает необходимость в наличии у класса-площадки собственного деструктора, поскольку никаких действий не требуется.
helicopterpad.hpp
#ifndef _HELICOPTERPAD_HPP_
#define _HELICOPTERPAD_HPP_
//************************************************************************
#include "point3d.hpp"
//************************************************************************
// Форвардное объявление класса-вертолета.
// Его содержимое не требуется для объявления класса-площадки.
class Helicopter;
//************************************************************************
// Класс-площадка
class HelicopterPad
{
/*-----------------------------------------------------------------*/
public:
/*-----------------------------------------------------------------*/
// Конструктор — задает координату местоположения, но не задает вертолета
HelicopterPad ( Point3D _location );
// Запрещенные конструктор копий и оператор присвоения
HelicopterPad ( const HelicopterPad & ) = delete;
HelicopterPad & operator = ( const HelicopterPad & ) = delete;
// Метод доступа к местоположению площадки
Point3D getLocation () const;
// Метод подтверждения приземления вертолета
bool hasLanded () const;
// Метод доступа к возможно приземлившемуся вертолету
Helicopter * getLanded () const;
// Метод регистрации приземления вертолета
void land ( Helicopter & _helicopter );
// Метод регистрации взлета вертолета
void unland ();
/*-----------------------------------------------------------------*/
private:
/*-----------------------------------------------------------------*/
// Координаты местоположения площадки.
// В отличие от вертолета, координаты площадки не могут изменяться
const Point3D m_location;
// Необязательная связь с приземлившимся объектом-вертолетом
Helicopter * m_pLanded;
/*-----------------------------------------------------------------*/
};
//************************************************************************
// Реализация метода доступа к местоположению площадки
inline Point3D
HelicopterPad::getLocation () const
{
return m_location;
}
//************************************************************************
// Реализация метода подтверждения приземления вертолета
inline bool HelicopterPad::hasLanded () const
{
// Если вертолет приземлился, значение указателя будет отлично от nullptr
return m_pLanded != nullptr;
}
//************************************************************************
// Реализация метода доступа к возможно приземлившемуся вертолету
inline Helicopter *
HelicopterPad::getLanded () const
{
// Даже если вертолет не приземлился, все корректно — метод вернет nullptr
return m_pLanded;
}
//************************************************************************
#endif // _HELICOPTERPAD_HPP_
helicopterpad.cpp
#include "helicopterpad.hpp"
#include "helicopter.hpp"
#include "point3d.hpp"
#include <stdexcept>
//************************************************************************
// Реализация конструктора
HelicopterPad::HelicopterPad ( Point3D _location )
: m_location( _location ),
m_pLanded( nullptr ) // Изначально вертолет не приземлялся
{
}
//************************************************************************
// Реализация метода регистрации приземления вертолета
void HelicopterPad::land ( Helicopter & _helicopter )
{
// Убеждаемся, что другой вертолет не приземлялся
if ( m_pLanded )
throw std::logic_error( "Something has already landed on this pad" );
// Подводим вертолет к точке приземления
_helicopter.moveTo( getLocation() );
// Создаем связь между объектами — // запоминаем адрес объекта-вертолета в объекте-площадке
m_pLanded = & _helicopter;
}
//************************************************************************
// Реализация метода регистрации взлета вертолета
void HelicopterPad::unland ()
{
// Убеждаемся, что вертолет приземлялся
if ( ! m_pLanded )
throw std::logic_error( "No helicopter is currently landed" );
// Вертолет должен взлететь на 7м строго над площадкой
m_pLanded->moveTo(
Point3D(
getLocation().getX(),
getLocation().getY(),
getLocation().getZ() + 7.0
)
);
// Разрываем связь между объектами обнулением указателя
m_pLanded = nullptr;
}
//************************************************************************
test_pads.cpp
#include "helicopterpad.hpp"
#include "helicopter.hpp"
#include <cassert>
int main ()
{
// Создаем вертолетную площадку
HelicopterPad * pHeliPad = new HelicopterPad( Point3D( 1.0, 2.0, 0.0 ) );
// Изначально на площадке никто не приземлен
assert( ! pHeliPad->hasLanded() );
// Создаем вертолет
Helicopter * pHelicopter = new Helicopter( 1 );
// Приземляем вертолет на площадке
pHeliPad->land( * pHelicopter );
// Убеждаемся, что на площадке находится наш вертолет
assert( pHeliPad->hasLanded() && pHeliPad->getLanded() == pHelicopter );
// Убеждаемся, что текущее местоположение вертолета совпадает с местом площадки
Point3D location = pHelicopter->getCurrentPosition();
assert( location == pHeliPad->getLocation() );
// Взлетаем
pHeliPad->unland();
// На площадке не должно остаться вертолета
assert( ! pHeliPad->hasLanded() );
// Координаты X/Y вертолета должны совпадать с координатами площадки,
// однако координата Z должна отличаться (вертолет взлетает идеально вверх)
Point3D newLocation = pHelicopter->getCurrentPosition();
assert( newLocation.getX() == location.getX() &&
newLocation.getY() == location.getY() &&
newLocation.getZ() > location.getZ() );
// Уничтожаем площадку и вертолет
delete pHeliPad;
delete pHelicopter;
}
