Ссылочная композиция — логическое объединение 


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



ЗНАЕТЕ ЛИ ВЫ?

Ссылочная композиция — логическое объединение



 

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

 

Если такая связь между объектами является постоянной, то, как правило, дочерний объект хранится по ссылке либо константной ссылке, которая передается в родительский объект при конструировании. Обычно, таким видам объектов не свойственно копирование и присвоение, и эти операции имеет смысл в явном виде запретить.

 

Ниже представлено логическое объединение между орудием (Weapon) и его типом, или моделью (WeaponType). Каждый экземпляр класса Weapon получает ссылку на тип орудия WeaponType в конструкторе, и эта ссылка сохраняется до конца жизни объекта орудия. Предполагается, что тип орудия просуществует дольше любого из орудий. Это ограничение должно обеспечиваться внешним по отношению к рассматриваемым классам кодом.

 

 

weapontype.hpp

 

#ifndef _WEAPONTYPE_HPP_

#define _WEAPONTYPE_HPP_

 

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

 

class WeaponType

{

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

 

public:

 

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

 

// Конструктор

WeaponType (double _caliber, int _maxAmmo);

 

// Удаленные конструктор копий и оператор присвоения

WeaponType (const WeaponType &) = delete;

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

 

// Метод доступа к калибру

double getCaliber () const;

 

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

int getMaxAmmo () const;

 

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

 

private:

 

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

 

// Калибр орудия

const double m_caliber;

 

// Максимальное число зарядов

const int m_maxAmmo;

 

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

 

};

 

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

 

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

inline double WeaponType::getCaliber () const

{

return m_caliber;

}

 

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

 

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

inline int WeaponType::getMaxAmmo () const

{

return m_maxAmmo;

}

 

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

 

#endif //_WEAPONTYPE_HPP_

 

 

weapontype.cpp

 

#include "weapontype.hpp"

 

#include <stdexcept>

 

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

 

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

WeaponType::WeaponType (double _caliber, int _maxAmmo)

: m_caliber(_caliber), m_maxAmmo(_maxAmmo)

{

// Инвариант: калибр является положительным числом

if (_caliber <= 0.0)

throw std::logic_error("Expecting a positive caliber");

 

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

if (_maxAmmo < 1)

throw std::logic_error("Expecting at least 1 as a maximum ammo");

}

 

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

 

 

weapon.hpp

 

#ifndef _WEAPON_HPP_

#define _WEAPON_HPP_

 

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

 

class WeaponType;

 

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

 

class Weapon

{

 

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

 

public:

 

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

 

// Конструктор

Weapon (const WeaponType & _type, int _initialAmmo = 0);

// ^ ссылка на дочерний объект приходит в конструкторе

 

// Удаленные конструктор копий и оператор присвоения

Weapon (const Weapon &) = delete;

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

 

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

const WeaponType & getType () const;

 

// Метод доступа к количеству оставшихся зарядов

int getCurrentAmmo () const;

 

// Метод зарядки орудия. Возвращает количество оставшихся зарядов

int loadAmmo (int _ammo);

 

// Методы определения полноты заряда / отсутствия зарядов

bool hasFullAmmo () const;

bool hasNoAmmo () const;

 

// Метод имитации выстрела орудия

bool tryShoot ();

 

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

 

private:

 

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

 

// Ссылка на дочерний объект — тип орудия

const WeaponType & m_type;

 

// Количество оставшихся зарядов

int m_currentAmmo;

 

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

 

};

 

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

 

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

inline const WeaponType &

Weapon::getType () const

{

return m_type;

}

 

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

 

// Реализация метода доступа к количеству оставшихся зарядов

Inline int

Weapon::getCurrentAmmo () const

{

return m_currentAmmo;

}

 

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

 

#endif //_WEAPON_HPP_

 

 

weapon.cpp

 

#include "weapon.hpp"

#include "weapontype.hpp"

 

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

 

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

Weapon::Weapon (const WeaponType & _type, int _initialAmmo)

: m_type(_type) // запоминаем ссылку на дочерний объект

, m_currentAmmo(_initialAmmo)

{

}

 

 

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

 

// Реализация метода определения полноты заряда

bool Weapon::hasFullAmmo () const

{

// Сравниваем количество оставшихся зарядов с

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

return m_currentAmmo == getType().getMaxAmmo();

// ^ извлекаем максимум из дочернего объекта

}

 

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

 

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

bool Weapon::hasNoAmmo () const

{

return m_currentAmmo == 0;

}

 

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

 

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

int Weapon::loadAmmo (int _ammo)

{

// Определяем количество не хватающих до полной загрузки зарядов

int maxAmmo = getType().getMaxAmmo();

int freeAmmoSpace = maxAmmo - m_currentAmmo;

 

// Достаточно ли имеется зарядов до полной загрузки?

if (_ammo >= freeAmmoSpace)

{

// Возвращаем число неиспользованных зарядов

m_currentAmmo = maxAmmo;

return _ammo - freeAmmoSpace;

}

Else

{

// Переданного количества зарядов не хватит для полной загрузки

m_currentAmmo += _ammo;

return 0;

}

}

 

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

 

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

bool Weapon::tryShoot ()

{

// Имеется ли хоть один заряд?

if (hasNoAmmo())

// Без зарядов стрелять трудно:-(

return false;

 

// Выстрел произведен. Уменьшаем число оставшихся зарядов на 1.

-- m_currentAmmo;

return true;

}

 

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

 

test_weapons.cpp

 

#include "weapon.hpp"

#include "weapontype.hpp"

 

#include <cassert>

 

int main ()

{

// Создаем тип орудия — калибр 125мм, максимум 5 зарядов

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

 

// Создаем два орудия данного типа без начального заряда

Weapon * pWeapon1 = new Weapon(* pType);

Weapon * pWeapon2 = new Weapon(* pType);

 

// Заряжаем первое орудие максимально, убеждаемся, что орудие забрало

// зарядов, соответствующее максимально возможному для типа орудия

int totalAmmo = 100;

totalAmmo = pWeapon1->loadAmmo(totalAmmo);

assert(totalAmmo == (100 - pType->getMaxAmmo()));

 

// Заряжаем второе орудие только 1 снарядом

pWeapon2->loadAmmo(1);

 

// Делаем выстрел из первого орудия, убеждаемся, что число зарядом уменьшилось на 1

assert(pWeapon1->getCurrentAmmo() == pType->getMaxAmmo());

bool success = pWeapon1->tryShoot();

assert(success && pWeapon1->getCurrentAmmo() == (pType->getMaxAmmo() - 1));

 

// Делаем выстрел из второго орудия

assert(pWeapon2->getCurrentAmmo() == 1);

success = pWeapon2->tryShoot();

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

assert(success && pWeapon2->hasNoAmmo());

 

// Второй выстрел из второго орудия не получится

success = pWeapon2->tryShoot();

assert(! success);

 

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

delete pWeapon1;

delete pWeapon2;

 

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

delete pType;

}

 



Поделиться:


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

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