Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

RFpro.ru: Программирование на C / C++


Хостинг портала RFpro.ru:
Московский хостер
Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64

РАССЫЛКИ ПОРТАЛА RFPRO.RU

Лучшие эксперты по данной тематике

Асмик Гаряка
Статус: Советник
Рейтинг: 11017
∙ повысить рейтинг »
Коцюрбенко Алексей aka Жерар
Статус: Советник
Рейтинг: 4030
∙ повысить рейтинг »
CradleA
Статус: Бакалавр
Рейтинг: 2112
∙ повысить рейтинг »

/ КОМПЬЮТЕРЫ И СОФТ / Программирование / C/C++

Номер выпуска:1781
Дата выхода:07.02.2013, 16:30
Администратор рассылки:Киселёва Алёна aka Verena (Академик)
Подписчиков / экспертов:97 / 68
Вопросов / ответов:1 / 1

Консультация # 187147: Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос: Здравствуйте! Прошу помощи в решении следующей задачи(Среда - Visual Studio, код прокомментировать): Разработать и реализовать класс «очередь», элементы которого содержат указатель на описатель некоторой математической функции. Очередь отображается вектором, ...


Консультация # 187147:

Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос:

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

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

Дата отправки: 04.02.2013, 15:48
Вопрос задал: TemHbli (Посетитель)
Всего ответов: 1
Страница онлайн-консультации »


Консультирует Micren (Профессор):

Здравствуйте, TemHbli!

Код :
Очередь организована в виде вектора. Голова очереди _head. К-во элементов _size.
Элементы вставляются в очередь последовательно, пока не исчерпается выделенный размер памяти для данных - _capacity. 
В этом случае выделяется удвоенный размер памяти.

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

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

 ⇓
[1][ ][ ][ ] _size=1

 ⇓
[1][2][ ][ ] _size=2

 ⇓
[1][2][3][ ] _size=3

 ⇓
[1][2][3][4] _size=4

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

       ⇓
[ ][ ][3][4] _head=2,_size=2

          ⇓
[ ][ ][ ][4] _head=3,_size=1

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

          ⇓
[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: http://rfpro.ru/upload/9151

Консультировал: Micren (Профессор)
Дата отправки: 06.02.2013, 02:01
Рейтинг ответа:

НЕ одобряю 0 одобряю!


Оценить выпуск | Задать вопрос экспертам

главная страница  |  стать участником  |  получить консультацию
техническая поддержка  |  восстановить логин/пароль

Дорогой читатель!
Команда портала RFPRO.RU благодарит Вас за то, что Вы пользуетесь нашими услугами. Вы только что прочли очередной выпуск рассылки. Мы старались. Пожалуйста, оцените его. Если совет помог Вам, если Вам понравился ответ, Вы можете поблагодарить автора - для этого в каждом ответе есть специальные ссылки. Вы можете оставить отзыв о работе портале. Нам очень важно знать Ваше мнение. Вы можете поближе познакомиться с жизнью портала, посетив наш форум, почитав журнал, который издают наши эксперты. Если у Вас есть желание помочь людям, поделиться своими знаниями, Вы можете зарегистрироваться экспертом. Заходите - у нас интересно!
МЫ РАБОТАЕМ ДЛЯ ВАС!



В избранное