Композиция с разрываемой связью 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Композиция с разрываемой связью



 

Некоторые виды отношений целое-часть не являются постоянными. Дочерний объект может прикрепляться к родительскому в течение его жизни, а при необходимости — отцепляться и прикрепляться к другому родительскому объекту. Такое поведение свойственно отношениям, в которых дочерний объект имеет существенную долю обязанностей по сравнению с родительским объектом, и имеется практический смысл в его существовании вне родительского либо с другим родителем. При этом родительский объект по-прежнему может отвечать за уничтожение дочернего.

 

Ниже представлен класс, моделирующий вертолет (Helicopter). Вертолет имеет уникальный числовой номер. Вертолет находится в конкретный момент времени по конкретным координатам и его нос направлен под конкретным углом относительно осей координат. На вертолет может быть установлено необязательное к наличию орудие (объект Weapon). При наличии орудия, вертолет может производить выстрелы, в противном случае — только летать.

 

С точки зрения хранения данных в памяти, единственным способом для реализации такой необязательной связи между объектами является хранение указателя на дочерний объект в памяти родительского. Указатель будет адресовать конкретный дочерний объект, если связь установлена. При отсутствии связи значение указателя будет равно nullptr.

 

Связь между объектами Helicopter и Weapon не является обязательной. Она может устанавливаться внешне через вызов метода installWeapon, а затем разрываться через вызов deinstallWeapon. Во избежание ошибок объект-вертолет должен проверять, что может быть установлено только одно орудие, а также гарантировать, что снять орудие можно только после его установки. Если орудие прикреплено к вертолету на момент его уничтожения, орудие уничтожается вместе с ним.

 

 

helicopter.hpp

 

#ifndef _HELICOPTER_HPP_

#define _HELICOPTER_HPP_

 

//************************************************************************

 

#include "point3d.hpp"

#include "vector3d.hpp"

 

//************************************************************************

 

// Форвардное объявление класса-орудия. При определении класса-вертолета,
// содержимое класса-орудия не используется. Лишь используется указатель на объект
// этого класса, что не требует полного определения.

//

// Не делаем #include "weapon.h" до момента реальной необходимости

//

// Однако мы включили определение класса-точки и класса-вектора,
// поскольку они используются по значению внутри класса-вертолет,
// а значит компилятору нужно знать их содержимое.

 

class Weapon;

 

//************************************************************************

 

class Helicopter

{

 

/*-----------------------------------------------------------------*/

 

public:

 

/*-----------------------------------------------------------------*/

 

 

// Конструктор — передаем номер, начальный угол и позицию, орудие не предусмотрено

Helicopter (

int _machineID

, Vector3D _initialAngle = Vector3D()

, Point3D _initialPosition = Point3D()

);

 

// Запрещенные конструктор копий и оператор присвоения

Helicopter (const Helicopter &) = delete;

Helicopter & operator = (const Helicopter &) = delete;

 

// Деструктор

~Helicopter ();

 

// Метод, возвращающий номер вертолета

int getMachineID () const;

 

// Метод подтверждения наличия орудия

bool hasWeapon () const;

 

// Метод доступа к установленному орудию

Weapon * getWeapon () const;

 

// Метод установки орудия

void installWeapon (Weapon & _weapon);

 

// Метод снятия орудия

void deinstallWeapon ();

 

// Метод, осуществляющий пробу выстрела по заданной целевой координате

bool tryShootingTargetAt (Point3D _p);

 

// Методы доступа и изменения текущей позиции

Point3D getCurrentPosition () const;

void moveTo (Point3D _p);

 

// Методы доступа и изменения текущего угла по отношению к координатным осям

Vector3D getCurrentAngle () const;

void turnTo (Vector3D _angle);

 

/*-----------------------------------------------------------------*/

 

private:

 

/*-----------------------------------------------------------------*/

 

// Дочерний объект-орудие – связь не является обязательной, может быть nullptr

Weapon * m_pWeapon;

 

// Угол направления носа вертолета

Vector3D m_currentAngle;

 

// Текущие координаты местоположения вертолета

Point3D m_position;

 

// Уникальный числовой номер вертолета

const int m_machineID;

 

/*-----------------------------------------------------------------*/

 

};

 

//************************************************************************

 

// Реализация метода, возвращающего номер вертолета

Inline int

Helicopter::getMachineID () const

{

return m_machineID;

}

 

 

//************************************************************************

 

// Реализация метода доступа к текущей позиции

inline Point3D

Helicopter::getCurrentPosition () const

{

return m_position;

}

 

//************************************************************************

 

// Реализация метода изменения текущей позиции

Inline void

Helicopter::moveTo (Point3D _p)

{

m_position = _p;

}

 

//************************************************************************

 

// Реализация метода доступа к текущему углу

inline Vector3D

Helicopter::getCurrentAngle () const

{

return m_currentAngle;

}

 

//************************************************************************

 

// Реализация метода изменения текущего угла

Inline void

Helicopter::turnTo (Vector3D _angle)

{

m_currentAngle = _angle;

}

 

//************************************************************************

 

// Реализация метода подтверждения наличия орудия

Inline

bool Helicopter::hasWeapon () const

{

// Если орудие установлено, значение указателя будет отлично от nullptr

return m_pWeapon!= nullptr;

}

 

//************************************************************************

 

// Реализация метода доступа к установленному орудию

Inline

Weapon * Helicopter::getWeapon () const

{

// Даже если орудия не установлено, все корректно — метод вернет nullptr

return m_pWeapon;

}

 

//************************************************************************

 

#endif //_HELICOPTER_HPP_

 

 

helicopter.cpp

 

#include "helicopter.hpp"

#include "weapon.hpp" // Включаем полное определение класса-орудия лишь сейчас,

// поскольку для реализации методов класса-вертолета используется

// содержимое класса-орудия (для выстрела, для уничтожения)

 

#include <stdexcept>

 

//************************************************************************

 

// Реализация конструктора

Helicopter::Helicopter (

int _machineID

, Vector3D _initialAngle

, Point3D _initialPosition

)

// Копируем номер, угол и координаты

: m_machineID(_machineID)

, m_currentAngle(_initialAngle)

, m_position(_initialPosition)

, m_pWeapon(nullptr) // <- Изначально орудие не устанавливается

{

}

 

//************************************************************************

 

// Реализация деструктора

Helicopter::~Helicopter ()

{

// Уничтожаем орудие, если оно установлено.

// Если орудия не установлено, ничего страшного, delete nullptr игнорируется

delete m_pWeapon;

}

 

//************************************************************************

 

// Реализация метода установки орудия

void Helicopter::installWeapon (Weapon & _weapon)

{

// Убеждаемся, что никакое другое орудие еще не было установлено

if (hasWeapon())

throw std::logic_error("Weapon is already installed on the helicopter");

 

// Создаем связь между объектами:
// запоминаем в объекте-вертолет адрес объекта-орудия

m_pWeapon = & _weapon;

}

 

//************************************************************************

 

// Реализация метода снятия орудия

void Helicopter::deinstallWeapon ()

{

// Убеждаемся, что орудие было установлено

if (! hasWeapon())

throw std::logic_error("Weapon was not installed on the helicopter");

 

// Разрываем связь между объектами через обнуление указателя

m_pWeapon = nullptr;

 

// Примечание: при таком разрыве связи внешний код должен гарантировать

// освобождение объекта-орудия, поскольку вертолет больше за него не отвечает

}

 

//************************************************************************

 

// Реализация метода, осуществляющего пробу выстрела по заданной целевой координате

bool Helicopter::tryShootingTargetAt(Point3D _p)

{

// Если орудия не установлено, выстрелить не получится

if (! hasWeapon())

return false;

 

// Изменяем угол носа вертолета таким образом, чтобы вертолет смотрел на цель

turnTo(

Vector3D(

_p.getX() - m_position.getX(),

_p.getY() - m_position.getY(),

_p.getZ() - m_position.getZ()

)

);

 

// Пробуем выстрелить из орудия.

// Логика учета количества зарядов уже учтена в реализации класса-орудия

return m_pWeapon->tryShoot();

}

 

//************************************************************************

 

test_helicopter.cpp

 

#include "helicopter.hpp"

#include "weapontype.hpp"

#include "weapon.hpp"

 

#include <cassert>

 

int main ()

{

// Создаем два объекта-вертолета

Helicopter * pHelicopter1 = new Helicopter(1);

Helicopter * pHelicopter2 = new Helicopter(2);

 

// Создаем тип орудия

WeaponType * pWeaponType = new WeaponType(125.0, 5);

 

// Вооружаем первый вертолет орудием с одним начальным зарядом

pHelicopter1->installWeapon(* new Weapon(* pWeaponType, 1));

assert(pHelicopter1->getWeapon()->getCurrentAmmo() == 1);

 

// Пробуем выстрелить c первого вертолета.

// Первый выстрел успешен, а орудие разряжено.

bool result = pHelicopter1->tryShootingTargetAt(Point3D(2.0, 2.0, 2.0));

assert(result && pHelicopter1->getWeapon()->hasNoAmmo());

 

// Пробуем выстрелить еще раз с первого вертолета.

// Второй выстрел завершается неудачей, поскольку нет зарядов в орудии

result = pHelicopter1->tryShootingTargetAt(Point3D(3.0, 3.0, 3.0));

assert(! result);

 

// Пробуем выстрелить со второго вертолета, однако терпим неудачу,

// поскольку никакого орудия на нем не установлено

result = pHelicopter2->tryShootingTargetAt(Point3D(4.0, 4.0, 4.0));

assert(! result);

 

// Куда же направлены носы наших вертолетов?

// - первый вертолет имеет вооружение, и поворачивается перед попыткой выстрела,

// соответственно, его нос направлен в сторону координаты последней цели

// - второй вертолет не имеет установленного орудия, и не поворачивается

assert(pHelicopter1->getCurrentAngle() == Vector3D(3.0, 3.0, 3.0));

assert(pHelicopter2->getCurrentAngle() == Vector3D(0.0, 0.0, 0.0));

 

// Уничтожаем оба вертолета. Орудие уничтожается вместе с первым вертолетом

delete pHelicopter1;

delete pHelicopter2;

 

// Уничтожаем тип орудия

delete pWeaponType;

}

 



Поделиться:


Последнее изменение этой страницы: 2017-02-17; просмотров: 127; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 13.59.243.194 (0.063 с.)