Консультация № 187147
04.02.2013, 15:48
220.00 руб.
0 2 1
Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос:

Здравствуйте! Прошу помощи в решении следующей задачи(Среда - Visual Studio, код прокомментировать):

Разработать и реализовать класс «очередь», элементы которого содержат указатель на описатель некоторой математической функции.
Очередь отображается вектором, память под который выделяется динамически. Для класса «очередь» предусмотреть необходимые конструкторы, деструктор и методы, в том числе операции занесения в очередь (в очередь включается копия аргумента) и выборки из очереди.
Математические функции задаются своими коэффициентами (вещественные одинарной точности). Должны поддерживаться следующие классы математических функций:
синусная тригонометрическая функция - имеет вид: A*sin (B*x+D) +С;
косинусная тригонометрическая функция - имеет вид: A*cos (B*x+D) +С;
Здесь А, В, С, D - коэффициенты функций.
Для каждой из функций реализовать необходимые конструкторы, деструктор и методы, в том числе виртуальные методы создания копии объекта, увеличения функции на константу (результат - новая функция) и вывода в поток соответствующей математической формулы (с помощью перегруженного оператора <<).
Написать программу иллюстрирующую работу разработанной иерархии классов. Разрешается использовать STL, математическую библиотеку и библиотеку обработки строк. Разработанная иерархия классов не должна обладать избыточностью.

Обсуждение

Неизвестный
06.02.2013, 01:48
общий
Объясните зачем нужны ВИРТУАЛЬНЫЕ методы создания копий объекта. Это имеет значение только для полиморфизма. Т.к. для остального хватит и конструктора копирования по умолчанию. Что там пишут в методичке?
Неизвестный
06.02.2013, 02:01
общий
это ответ
Здравствуйте, TemHbli!
Код:
Очередь организована в виде вектора. Голова очереди _head. К-во элементов _size.
Элементы вставляются в очередь последовательно, пока не исчерпается выделенный размер памяти для данных - _capacity.
В этом случае выделяется удвоенный размер памяти.

Как это работает:
Вначале _head=0([$8659$]),_size=0,_capacity=4
[$8659$]
[ ][ ][ ][ ]

Элементы добавляются последовательно в позицию (_head+_size)%_capacity. Т.е. в незанятую позицию(хвост) по кругу.

[$8659$]
[1][ ][ ][ ] _size=1

[$8659$]
[1][2][ ][ ] _size=2

[$8659$]
[1][2][3][ ] _size=3

[$8659$]
[1][2][3][4] _size=4

Извлечение элементов из головы очереди происходит с изменением _head
[$8659$]
[ ][2][3][4] _head=1,_size=3

[$8659$]
[ ][ ][3][4] _head=2,_size=2

[$8659$]
[ ][ ][ ][4] _head=3,_size=1

Если теперь вставить элемент то будет

[$8659$]
[5][ ][ ][4] _head=3,_size=2

И.т.д.


Программа. Проверял Microsoft Visual Studio 2012.
main.cpp
Код:
#include <locale>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "function_queue.h"
#include "sin_function.h"
#include "cos_function.h"
#include "function_queue.h"

// Количество тестируемых функций
const size_t COUNT=5;

// Генерирует целое в диапазоне [a,b)
int rand_int(int a,int b)
{
return a+std::rand()%(b-a);
}

// Генерирует вещественное [a,b)
double rand_double(double a,double b)
{
return std::rand()/static_cast<double>(RAND_MAX)*(b-a)+a;
}

int main()
{
// Инициализация генератора случайных чисел
std::srand(static_cast<unsigned int>(std::time(0)));
std::locale::global(std::locale(""));

// Генерируем случайным образом функции
std::cout<<"Генерируем случайным образом "<<COUNT<<" функций и поместим указатели на них в очередь"<<std::endl;
// Наша очередь
function_queue queue;

for(size_t i=0;i<COUNT;++i)
{
// Коэффициенты
double a=rand_double(-5,5),
b=rand_double(-1,1),
c=rand_double(-2,2),
d=rand_double(-0.5,0.5);
// Генерируем целое 0 или 1
switch(rand_int(0,2))
{
// Если 0 то косинусная ф-я
case 0:
queue.push(new sin_function(a,b,c,d));
break;
// Если 1 то синусная
case 1:
queue.push(new cos_function(a,b,c,d));
break;
}
}

// Выведем всю очередь
std::cout<<"Получили очередь:\n"<<queue<<"\nВсего: "<<queue.size()<<" элементов\nРазберем поэлементно:\n";
// Извлечем из очереди поэлементно
while(queue.size())
{
// Указатель на ф-ю. Используем полиморфизм.
base_function* func=queue.pop();
double x=rand_double(-10,10);
std::cout<<"f(x)="<<*func<<"; f("<<x<<")="<<(*func)(x)<<std::endl;
// Освободим память за ненадобностью
delete func;
}

system("PAUSE");
return 0;
}

base_function.h
Код:
#pragma once
#include <iostream>
#include <valarray>
#include <string>
#include <sstream>

// Базовый класс для функций
class base_function
{
public:
// Конструктор. vars - количество коэффициентов
base_function(size_t vars);
virtual ~base_function(void);
// Получить значение ф-ии по аргументу
virtual double operator()(double x)=0;
// Преобразовать в строкоый вид
virtual std::string to_string() const=0;
// Клонирование объекта
virtual base_function* clone() const=0;
// Увеличение ф-и на константу
virtual base_function* add_const(double delta) const=0;
protected:
std::valarray<double> _vars;
friend class function_queue;
};

// Оператор вывода в поток
template<class Elem>
std::basic_ostream<Elem>& operator<<(std::basic_ostream<Elem>& stream,const base_function& func)
{
std::basic_stringstream<Elem> sstr;
sstr.imbue(stream.getloc());
std::string str=func.to_string();
for(std::string::const_iterator it=str.begin(),end=str.end();it!=end;++it)
{
sstr<<sstr.widen(*it);
}
return stream<<sstr.str();
}

base_function.cpp
Код:
#include "base_function.h"


base_function::~base_function(void)
{
}

base_function::base_function(size_t count)
:_vars(count)
{

}

cos_function.h
Код:
#pragma once
#include <string>
#include "base_function.h"

class cos_function :
public base_function
{
public:
cos_function(double a,double b,double c,double d);
virtual ~cos_function(void);
virtual double operator()(double x);
virtual std::string to_string() const;
virtual base_function* add_const(double delta) const;
virtual base_function* clone() const;
};

cos_function.cpp
Код:
#include <cmath>
#include <sstream>
#include "cos_function.h"


cos_function::cos_function(double a,double b,double c,double d)
:base_function(4)
{
_vars[0]=a;
_vars[1]=b;
_vars[2]=c;
_vars[3]=d;
}


cos_function::~cos_function(void)
{
}

double cos_function::operator()( double x )
{
return _vars[0]*std::cos(_vars[1]*x+_vars[3])+_vars[2];
}

std::string cos_function::to_string() const
{
std::stringstream sstr;
sstr<<_vars[0]<<"*cos("<<_vars[1]<<"*x"<<std::showpos<<_vars[3]<<")"<<_vars[2];
return sstr.str();
}

base_function* cos_function::add_const(double delta) const
{
cos_function* res=new cos_function(*this);
res->_vars[2]+=delta;
return res;
}

base_function* cos_function::clone() const
{
return new cos_function(*this);
}

sin_function.h
Код:
#pragma once
#include "base_function.h"

// Синусная ф-я
class sin_function :
public base_function
{
public:
sin_function(double a,double b,double c,double d);
virtual ~sin_function(void);
virtual double operator()(double x);
virtual std::string to_string() const;
virtual base_function* add_const(double delta) const;
virtual base_function* clone() const;
};

sin_function.cpp
Код:
#include <cmath>
#include <iomanip>
#include <sstream>
#include "sin_function.h"


sin_function::sin_function(double a,double b,double c,double d)
:base_function(4)
{
_vars[0]=a;
_vars[1]=b;
_vars[2]=c;
_vars[3]=d;
}


sin_function::~sin_function(void)
{
}

double sin_function::operator()( double x )
{
return _vars[0]*std::sin(_vars[1]*x+_vars[3])+_vars[2];
}

std::string sin_function::to_string() const
{
std::stringstream sstr;
sstr<<_vars[0]<<"*sin("<<_vars[1]<<"*x"<<std::showpos<<_vars[3]<<")"<<_vars[2];
return sstr.str();
}

base_function* sin_function::add_const( double delta ) const
{
sin_function* res=new sin_function(*this);
res->_vars[2]+=delta;
return res;
}

base_function* sin_function::clone() const
{
return new sin_function(*this);
}

function_queue.h
Код:
#pragma once
#include <iostream>
#include <sstream>
#include "base_function.h"

// Класс «очередь», элементы которого содержат указатель на описатель некоторой математической функции
// Очередь отображается вектором, память под который выделяется динамически.
// Данные в очереди организованы в виде кольца, где _head - индекс головы очереди
class function_queue
{
public:
function_queue(void);
~function_queue(void);
// Поместить указатель в очередь
void push(base_function* func);
// Извлечь указатель из очереди
base_function* pop();
// Количество элементов в очереди
size_t size(void) const;
private:
// Минимальная емкость очереди
static const size_t MIN_CAPACITY=4;
// Емкость, голова, количество элементов
size_t _capacity,_head,_size;
// Сами данные - массив указателей
base_function** _data;
function_queue(const function_queue&);
function_queue& operator=(const function_queue&);
// Изменяет размер
void _resize(size_t new_capacity);
template<class Elem> friend std::basic_ostream<Elem>& operator<<(std::basic_ostream<Elem>& stream,const function_queue& queue);
};

// Оператор вывода очереди в поток
template<class Elem>
std::basic_ostream<Elem>& operator<<(std::basic_ostream<Elem>& stream,const function_queue& queue)
{
std::basic_stringstream<Elem> sstr;
sstr.imbue(stream.getloc());
sstr<<sstr.widen('[');
for(size_t i=queue._head,count=queue._size;count;)
{
sstr<<*queue._data[i];
i=(i+1)%queue._capacity;
if(--count)
{
sstr<<sstr.widen(',');
}
}
sstr<<sstr.widen(']');
return stream<<sstr.str();
}

function_queue.cpp
Код:
#include <memory>
#include <stdexcept>
#include "function_queue.h"


function_queue::function_queue(void)
:_data(0)
,_capacity(0)
,_head(0)
,_size(0)
{
}


function_queue::~function_queue(void)
{
if(_data)
{
delete[] _data;
}
}


void function_queue::push(base_function* func)
{
// Если емкость очереди исчерпана
if(!(_size<_capacity))
{
// Удвоим емкость
_resize(_capacity<<1);
}
// Место куда будет помещен элемент
size_t to=(_head+_size)%_capacity;
_data[to]=func;
++_size;
}


base_function* function_queue::pop()
{
// Если есть что извлекать из очереди
if(_size>0)
{
--_size;
base_function* res=_data[_head];
_head=(_head+1)%_capacity;
return res;
}
else
{
throw std::out_of_range("queue is empty");
}
}

// Изменение размера вектора
void function_queue::_resize(size_t new_capacity)
{
if(new_capacity<MIN_CAPACITY)
{
new_capacity=MIN_CAPACITY;
}
// Выделяем новый блок памяти
base_function** new_data=new base_function*[new_capacity];
if(_data)
{
// Копируем данные в новый блок
// Куда копируем
base_function** to=new_data;
// Перебор элементов
for(size_t count=_size;count;--count,_head=(_head+1)%_capacity)
{
*to++=_data[_head];
}
_head=0;
delete[] _data;
}
_data=new_data;
_capacity=new_capacity;
}

inline size_t function_queue::size(void) const
{
return _size;
}


Проект для MS VS 2012: https://rfpro.ru/upload/9151
Форма ответа