- •Ооп: Лекция 9. Композиция объектов.
- •Композиция объектов
- •Простейшая композиция по значению
- •Множественная композиция по значению
- •Ссылочная композиция — логическое объединение
- •Композиция с разрываемой связью
- •Разрываемая ссылочная композиция
- •Недетерминированная множественность композиции
- •Множественная композиция объектов-сущностей
- •Полные примеры из лекции
Множественная композиция по значению
Кратность дочерних объектов может быть множественной. В таком случае используются массивы дочерних объектов. Если количество объектов заранее известно, массив фиксированного размера размещается непосредственно в родительском объекте. Чаще количество объектов заранее неизвестно и определяется во время выполнения. При этом количество передается в конструкторе, который выделяет динамический блок памяти для хранения желаемого количества дочерних объектов, а в родительском объекте сохраняется указатель на начало блока. Разумеется, родительский объект становится ответственным за уничтожение выделенного блока памяти, что следует в явном виде реализовать в деструкторе. Таким действиям в родительском классе обычно сопутствуют определения конструкторов копий и перемещения, а также соответствующих операторов присвоения и перемещения.
Ниже представлен класс для многоугольника, состоящий из множества точек (в показанном примере, из 4 точек конкретно):
polygon.hpp
#ifndef _POLYGON_HPP_
#define _POLYGON_HPP_
//************************************************************************
#include "point3d.hpp"
//************************************************************************
class Polygon
{
/*-----------------------------------------------------------------*/
public:
/*-----------------------------------------------------------------*/
// Конструктор — принимает количество точек
Polygon ( int _nPoints );
// Конструктор копий
Polygon ( const Polygon & _p );
// Конструктор перемещения
Polygon ( Polygon && _p );
// Деструктор
~Polygon ();
// Оператор присвоения
Polygon & operator = ( const Polygon & _p );
// Оператор перемещения
Polygon & operator = ( Polygon && _p );
// Метод доступа к количеству точек
int getNPoints () const;
// Методы доступа к точке по индексу
const Point3D & getPoint ( int index ) const;
Point3D & getPoint ( int _index );
// Метод вычисления длины сторон многоугольника
double getPerimeter () const;
/*-----------------------------------------------------------------*/
private:
/*-----------------------------------------------------------------*/
// Начала блока хранения точек
Point3D * m_points;
// Количество точек
int m_nPoints;
/*-----------------------------------------------------------------*/
};
//************************************************************************
// Реализация метода доступа к количеству точек
inline int Polygon::getNPoints () const
{
return m_nPoints;
}
//************************************************************************
#endif // _POLYGON_HPP_
polygon.cpp
#include "polygon.hpp"
#include <stdexcept>
//************************************************************************
// Реализация конструктора
Polygon::Polygon ( int _nPoints )
: m_nPoints( _nPoints ) // Запоминаем количество точек
{
// Проверяем инвариант - как минимум 3 точки! if ( _nPoints < 3 )
throw std::logic_error( "Expecting at least 3 points in polygon" );
// Выделяем блок для хранения точек и запоминаем адрес // его начала в объекте-многоугольнике
m_points = new Point3D[ m_nPoints ];
}
//************************************************************************
// Реализация конструктора копий
Polygon::Polygon ( const Polygon & _p )
{
// Извлекаем количество точек из объекта-оригинала
m_nPoints = _p.m_nPoints;
// Выделяем блок для хранения точек и // запоминаем адрес его начала в объекте-многоугольнике
m_points = new Point3D[ m_nPoints ];
// Копируем координаты точек
for ( int i = 0; i < m_nPoints; i++ )
m_points[ i ] = _p.m_points[ i ];
}
//************************************************************************
// Реализация конструктора перемещения
Polygon::Polygon ( Polygon && _p )
{
// Извлекаем количество точек из объекта-оригинала
m_nPoints = _p.m_nPoints;
// "Отбираем" у объекта-оригинала блок данных
m_points = _p.m_points;
_p.m_points = nullptr;
}
//************************************************************************
// Реализация деструктора
Polygon::~Polygon ()
{
// Освобождаем блок для хранения точек
delete[] m_points;
}
//************************************************************************
// Реализация оператора присвоения
Polygon & Polygon::operator = ( Polygon const & _p )
{
// Защита от присвоения самому себе
if ( this == & _p )
return * this;
// Освобождаем предыдущий блок с точками
delete[] m_points;
// Извлекаем количество точек из объекта в правой части присвоения
m_nPoints = _p.m_nPoints;
// Выделяем блок для хранения точек и запоминаем адрес его начала // в объекте-многоугольнике
m_points = new Point3D[ m_nPoints ];
// Копируем координаты точек
for ( int i = 0; i < m_nPoints; i++ )
m_points[ i ] = _p.m_points[ i ];
// Возвращаем ссылку на себя
return * this;
}
//************************************************************************
// Реализация оператора перемещения
Polygon & Polygon::operator = ( Polygon && _p )
{
// Защита от перемещения в самого себя
if ( this == & _p )
return * this;
// Осуществляем обмен переменными
std::swap( m_nPoints, _p.m_nPoints );
std::swap( m_points, _p.m_points );
// Возвращаем ссылку на себя
return * this;
}
//************************************************************************
// Реализация метода доступа к точке по индексу без права на запись
const Point3D & Polygon::getPoint ( int _index ) const
{
if ( _index >= 0 && _index < getNPoints() )
return m_points[ _index ];
else
throw std::logic_error( "Point index is out of range" );
}
//************************************************************************
// Реализация метода доступа к точке по индексу c правом на запись
Point3D & Polygon::getPoint ( int _index )
{
if ( _index >= 0 && _index < getNPoints() )
return m_points[ _index ];
else
throw std::logic_error( "Point index is out of range" );
}
//************************************************************************
// Реализация метода вычисления длины сторон многоугольника
double Polygon::getPerimeter () const
{
// Суммируем расстояния между соседними точками многоугольника
double total = 0.0;
for ( int i = 0; i < m_nPoints - 1; i++ )
total += m_points[ i ].distanceTo( m_points[ i + 1 ] );
return total;
}
//************************************************************************
