Upload
igor-shkulipa
View
116
Download
1
Embed Size (px)
Citation preview
Темы лекции: Распределители, функторы, адаптеры, алгоритмы.
Практическое задание: Функторы, адаптеры, алгоритмы.
Тренер: Игорь Шкулипа, к.т.н.
С++ Библиотеки STL и Qt. Занятие 2
http://www.slideshare.net/IgorShkulipa 2
Распределители памяти
Каждый контейнер имеет распределитель памяти (allocator),который используется при выделении памяти под элементы контейнера ипредназначен для того, чтобы освободить пользователей контейнеров, отподробностей физической организации памяти.
Стандартная библиотека обеспечивает стандартный распределительпамяти, заданный стандартным шаблоном allocator из заголовочногофайла <memory>, который выделяет память при помощи операции new( ) и по умолчанию используется всеми стандартными контейнерами.
Класс allocator обеспечивает стандартные способы выделения иперераспределения памяти, а также стандартные имена типов дляуказателей и ссылок.
Пользователь может задать свои распределители памяти,предоставляющие альтернативный доступ к памяти.
Стандартные контейнеры и алгоритмы получают память и обращаются кней через средства, обеспечиваемые распределителем памяти.
http://www.slideshare.net/IgorShkulipa 3
Класс распределителя
template <class T> class allocator {
public:
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
allocator(); ~allocator();
pointer address(reference x);
const_pointer const_address(const_reference x);
pointer allocate(size_type n);
void deallocate(pointer p);
size_type init_page_size();
size_type max_size();
};
class allocator<void> {
public:
typedef void* pointer;
allocator();
~allocator();
};
http://www.slideshare.net/IgorShkulipa 4
Функторы и предикаты
Функторы и предикаты - это классы, объекты которых похожи нафункцию (в них перегружен оператор () ):
• предикат - оператор () должен возвращать значение типа bool• функтор - у оператора () тип возвращаемого значения должен
быть отличным от bool
Предикат:struct cmp
{
bool operator ()(int a, int b) const
{
return a < b;
}
}
Функтор:struct sum
{
int operator ()(int a, int b) const
{
return (a + b) * (a + b);
}
}
http://www.slideshare.net/IgorShkulipa 5
Функторы STL
В STL уже реализовано много полезных функторов:
• minus
• plus
• multip
• divides
• modulus
• logical_or
• logical_and
• logical_not
• less
• grater
• less_equal
• grater_equal
• not_equal
• equal_to
Пример. Сортировка вектора в обратном порядке:
vector<int> v=…;
sort(v.begin(), v.end(), grater<int>());
http://www.slideshare.net/IgorShkulipa 6
Strategy
Паттерн Strategy предназначенный для определения семействаалгоритмов и инкапсуляции каждого из них и обеспечения ихвзаимозаменяемости.
Переносит в отдельную иерархию классов все детали, связанныес реализацией алгоритмов.
http://www.slideshare.net/IgorShkulipa 7
Пример
class IStrategy
{
public:
virtual void Use()=0;
protected:
void WakeUp() {cout<<"Wake up.\n";}
void Shower() {cout<<"Take shower.\n";}
void Dress() {cout<<"Dress.\n";}
void GoToBusStop() {cout<<"Go to bus stop.\n";}
void Wait() {cout<<"Wait.\n";}
void Arrive() {cout <<"Arrive.\n";};
void DoWork() {cout <<"Do work.\n";}
void DoExercises() {cout <<"Do exercises.\n";}
void Walk() {cout<<"Walk.\n";}
void GoOut() {cout<<"Go out.\n";}
void GoToPark() {cout<<"Go to park.\n";};
};
http://www.slideshare.net/IgorShkulipa 8
Классы конкретных стратегий
class GoToWorkStrategy: public IStrategy {
public:
virtual void Use() {
WakeUp(); Shower(); Dress(); GoOut();
GoToBusStop(); Wait(); Arrive(); DoWork();
}};
class GoWalkStrategy: public IStrategy {
public:
virtual void Use() {
GoOut(); GoToPark(); Walk();
}};
class GoToGymStrategy: public IStrategy {
public:
virtual void Use() {
GoOut(); GoToBusStop(); Arrive(); DoExercises();
}};
http://www.slideshare.net/IgorShkulipa 9
Клиент стратегий
class IStrategyClient
{
public:
virtual void UseStrategy()=0;
virtual void SetStrategy(IStrategy* st){_strategy=st;};
protected:
IStrategy* _strategy;
};
class StrategyClient1: public IStrategyClient
{
public:
StrategyClient1(){}
void UseStrategy()
{
_strategy->Use();
}
};
http://www.slideshare.net/IgorShkulipa 10
Использование стратегий
int main()
{
IStrategyClient* stClient=new StrategyClient1();
stClient->SetStrategy(new GoToWorkStrategy());
stClient->UseStrategy();
cout<<"\n";
stClient->SetStrategy(new GoToGymStrategy());
stClient->UseStrategy();
cout<<"\n";
stClient->SetStrategy(new GoWalkStrategy);
stClient->UseStrategy();
}
Результат:Wake up.
Take shower.
Dress.
Go out.
Go to bus stop.
Wait.
Arrive.
Do work.
Go out.
Go to bus stop.
Arrive.
Do exercises.
Go out.
Go to park.
Walk.
http://www.slideshare.net/IgorShkulipa 11
Реализация с функторами. Базовая стратегия
class IStrategy
{
public:
virtual double operator()(double a, double b)=0;
protected:
double Add(double a, double b) {return a+b;}
double Sub(double a, double b) {return a-b;}
double Div(double a, double b) {return a/b;}
double Mul(double a, double b) {return a*b;}
};
http://www.slideshare.net/IgorShkulipa 12
Реализация с функторами. Конкретные стратегии
class A2PlusB2Strategy: public IStrategy {
public:
double operator()(double a, double b) {
return Add(Mul(a,a),Mul(b,b));
}};
class A2MinusB2Strategy: public IStrategy {
public:
double operator()(double a, double b) {
return Sub(Mul(a,a),Mul(b,b));
}};
http://www.slideshare.net/IgorShkulipa 13
Реализация с функторами. Клиенты стратегий
class IStrategyClient
{
public:
virtual void PrintUsingStrategy
(double a, double b, IStrategy* st)=0;
};
class StrategyClient: public IStrategyClient
{
public:
StrategyClient(){}
void PrintUsingStrategy(double a, double b, IStrategy* st)
{
cout<<a<<" "<<b<<" "<<(*st)(a,b)<<"\n";
}
};
http://www.slideshare.net/IgorShkulipa 14
Реализация с функторами. Использование
int main(int argc, char* argv[])
{
StrategyClient* stc=new StrategyClient();
stc->PrintUsingStrategy(5,4,new A2MinusB2Strategy());
stc->PrintUsingStrategy(5,4,new A2PlusB2Strategy());
return 0;
}
5 4 9
5 4 41
http://www.slideshare.net/IgorShkulipa 15
Адаптер
Паттерн Adapter, представляет собой программную обертку надсуществующими классами, преобразуя их интерфейсы к виду,пригодному для последующего использования.
Пусть класс, интерфейс которого нужно адаптировать к нужномувиду, имеет имя Adaptee. Для решения задачи преобразованияего интерфейса паттерн Adapter вводит следующую иерархиюклассов:
◦ Виртуальный базовый класс Target. Здесь объявляетсяпользовательский интерфейс подходящего вида. Только этотинтерфейс доступен для пользователя.
◦ Производный класс Adapter, реализующий интерфейс Target.В этом классе также имеется указатель или ссылка наэкземпляр Adaptee. Паттерн Adapter использует этотуказатель для перенаправления клиентских вызовов вAdaptee. Так как интерфейсы Adaptee и Target несовместимымежду собой, то эти вызовы обычно требуютпреобразования.
http://www.slideshare.net/IgorShkulipa 16
Пример. Преобразование строки в структуру
class InputStringFullName {
protected:
string _strText;
public:
InputStringFullName() {
_strText="";
}
void Input() {
cout<<"Input Full Name (Surname Name MiddleName): ";
char* cstr=new char;
cin.getline(cstr, 9999, '\n');
_strText=string(cstr);
}
string GetText(){return _strText;}
};
http://www.slideshare.net/IgorShkulipa 17
Класс структуры
class FullName {
private:
string _strName; string _strSurname; string _strMiddle;
public:
FullName(string strSurname, string strName, string strMiddleName) {
_strName=strName; _strSurname=strSurname; _strMiddle=strMiddleName;
}
void Print() {
cout<<"Name: "<<_strName<<"\n";
cout<<"Middle Name: "<<_strMiddle<<"\n";
cout<<"Surname: "<<_strSurname<<"\n";
}
string GetName() {return _strName;}
string GetSurname() {return _strSurname;}
string GetMiddle() {return _strMiddle;}
void SetName(string strText) {_strName=strText;}
void SetSurname(string strText) {_strSurname=strText;}
void SetMiddle(string strText) {_strMiddle=strText;}
};
http://www.slideshare.net/IgorShkulipa 18
Класс-адаптер
class FullNameAdapter: public InputStringFullName
{
public:
FullNameAdapter(InputStringFullName* stringFullName)
{
_strText=stringFullName->GetText();
}
FullName* GetFullName()
{
unsigned iFirstSpace=_strText.find_first_of(" ");
string strSurname=_strText.substr(0,iFirstSpace);
unsigned iSecondSpace=
_strText.substr(iFirstSpace+1).find_first_of(" ")+iFirstSpace+1;
string strName=_strText.substr(iFirstSpace, iSecondSpace-iFirstSpace);
string strMiddle=_strText.substr(iSecondSpace);
return new FullName(strSurname, strName, strMiddle);
}
};
http://www.slideshare.net/IgorShkulipa 19
Использование адаптера
int main()
{
InputStringFullName* isfn=new InputStringFullName();
isfn->Input();
FullNameAdapter* fna=new FullNameAdapter(isfn);
FullName* fn=fna->GetFullName();
fn->Print();
}
Результат:Input Full Name (Surname Name MiddleName): Ivanov Petr Sidorovich
Name: Petr
Middle Name: Sidorovich
Surname: Ivanov
http://www.slideshare.net/IgorShkulipa 20
Адаптеры STL
Адаптеры - шаблонные классы, которые обеспечивают отображенияинтерфейса. Например, insert_iterator обеспечивает адаптер синтерфейсом итератора вывода.
Адаптеры контейнеров:
• Часто бывает полезно обеспечить ограниченные интерфейсыконтейнеров. Библиотека предоставляет stack, queue иpriority_queue через адаптеры, которые могут работать сразличными типами последовательностей.
Адаптеры функций:
• Функциональные адаптеры работают только с классамифункциональных объектов с определёнными типамипараметров и типом результата.
Адаптеры итераторов:
• Обратные итераторы• Итераторы вставки
http://www.slideshare.net/IgorShkulipa 21
Пример. Адаптер «Стек»template <class Container>
class stack {
friend bool operator==(const stack<Container>& х, const stack<Container>& y);
friend bool operator<(const stack<Container>& х, const stack<Container>& y);
public:
typedef Container::value_type value_type;
typedef Container::size_type size_type;
protected:
Container c;
public:
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
value_type& top() { return c.back(); }
const value_type& top() const { return c.back(); }
void push(const value_type& х) { с.push_back(х); }
void pop() { c.pop_back(); }
};
template <class Container>
bool operator==(const stack <Container>& х, const stack<Container>& y)
{ return х.с == у.с;}
template <class Container>
bool operator<(const stack<Container>& х, const stack<Container>& y)
{ return х.с < у.с; }
http://www.slideshare.net/IgorShkulipa 22
Алгоритмы
В STL существует множество готовых алгоритмов. Они позволяютсортировать данные в массиве, искать в нем какое-либо значение,менять элементы местами и т.д. Для их работы необходимоподключить <algorithm> в начале программы.
Алгоритмы реализованы в виде функций библиотеки.
http://www.slideshare.net/IgorShkulipa 23
Микро-алгоритмы
• swap(T &a, T &b) - Меняет местами значения двух элементов.
• iter_swap(It p, It q) - Меняет местами значения элементов, на
которые указывают итераторы.
• max(const T &a, const T &b ) - Возвращает максимальный
элемент.
• min(const T &a, const T &b ) - Возвращает минимальный
элемент.
У этих алгоритмов есть версии с тремя параметрами. Третий параметрпринимает бинарный предикат, задающий упорядоченностьобъектов.
http://www.slideshare.net/IgorShkulipa 24
Алгоритмы, не модифицирующие последовательности
• size_t count(It p, It q, const T &x) - Возвращает, сколько раз
элемент со значением x входит в последовательность, заданнуюитераторами p и q.
• size_t count_if(It p, It q, Pr pred) - Возвращает, сколько раз
предикат pred возвращает значение true.
Например, count_if(p, q, divides_by(8)) вернет, сколько элементов
кратно 8;
http://www.slideshare.net/IgorShkulipa 25
Алгоритмы поиска
• find(It p, It q, const T &x) - Возвращает итератор на первое
вхождение элемента x в последовательность, заданную итераторами pи q.
• find_if(It p, It q, Pr pred) - Возвращает итератор на первый
элемент, для которого предикат pred вернул значение true.
• find_first_of(It p, It q, Itr i, Itr j) - Возвращает итератор на
первое вхождение любого элемента из последовательности, заданнойитераторами i и j, в последовательность, заданную итераторами p и q.Последовательности могут быть разных типов (например std::vector иstd::list).
• min_element(It p, It q) - Возвращает итератор на минимальный
элемент последовательности.
• max_element(It p, It q) - Возвращает итератор на максимальный
элемент последовательности.
• equal(It p, It q, Itr i) - Сравнивает две последовательности на
эквивалентность. Вторая последовательность задается однимитератором, так как последовательности должны быть одинаковойдлины. Если вторая короче, то undefined behaviour.
http://www.slideshare.net/IgorShkulipa 26
Алгоритмы поиска
• pair <It, Itr> mismach(It p, It q, Itr i) - Возвращает пару
итераторов, указывающую на первое несовпадениепоследовательностей.
• for_each(It p, It q, F func) - Для каждого элемента
последовательности применяет функтор func. Возвращаемое значениефунктора после каждого применения игнорируется.
• bool binary_search(It p, It q, const T &x) - Возвращает true,
если в упорядоченной последовательности есть элемент, значениекоторого равно x, false в противном случае.
• Если хотим получить итератор на элемент со значением x, то нужноиспользовать алгоритмы lower_bound(It p, It q, const T &x),upper_bound(It p, It q, const T &x), equal_range(It p, It q,
const T &x), которые выполняют то же, что и одноименные методы
для контейнера std::set.
Все эти алгоритмы имеют версии с параметром, принимающим бинарный предикат, задающий упорядоченность объектов.
http://www.slideshare.net/IgorShkulipa 27
Модифицирующие алгоритмы• fill(It p, It q, const T &x), fill_n(It p, Size n, const T &x) -
Заполняют последовательность значениями, равными значению x.• generate(It p, It q, F gen), generate_n(It p, Size n, F gen) - Заполняют
последовательность значениями, сгенерированными функтором gen (например,генератором случайных чисел).
• random_shuffle(It p, It q) - Перемешивает элементы в случайном порядке.• copy(It p, It q, Itr out) - Копирует значения элементов
последовательности, заданной итераторами p и q, в последовательность,начинающуюся с итератора out.
• copy_backward(It p, It q, Itr out) - Копирует элементы
последовательности, заданной итераторами p и q, в последовательность,заканчивающуюся итератором out.
• remove_copy(It p, It q, Itr out, const T &x) - Копирует значения
элементов из последовательности, заданной итераторами p и q, впоследовательность, начинающуюся с итератора out, за исключением элементов,значения которых равны значению x.
• remove_copy_if(It p, It q, Itr out, Pr pred) - Копирует значения
элементов из последовательности, заданной итераторами p и q, впоследовательность, начинающуюся с итератора out, за исключением элементов,для которых предикат pred возвращает значение true.
• reverse(It p, It q) - Переставляет элементы в обратном порядке.• reverse_copy(It p, It q, Itr out) - Копирует значения элементов в обратном
порядке.• rotate(It p, It middle, It q) - Сдвигает элементы последовательности так,
что элемент, на который указывает итератор middle становится первым.
http://www.slideshare.net/IgorShkulipa 28
Модифицирующие алгоритмы
• remove(It p, It q, const T &x) - Удаляет из последовательности элементы,
значения которых совпадают по значению с x. Возвращает итератор на новыйконец последовательности.
• unique(It p, It q), unique(It p, It q, Pr pred) - Удаляет одинаковые
подряд идущие элементы, оставляя только по одному элементу для каждогозначения. Элементы последовательности должны быть отсортированы. Работаетаналогично алгоритмам remove и remove_if, оставляя в начале толькоуникальные элементы, а в конце - то, что осталось. В качестве третьегопараметра можно передавать предикат, сравнивающий два элемента ивозвращающий true, если элементы равны, и false в противном случае.
• unique_copy(It p, It q, Itr out), unique_copy(It p, It q, Itr out, Pr
pred) - Копирует уникальные элементы в последовательность, начинающуюся с
итератора out.
• transform(It p, It q, Itr out, F func) - К каждому элементу входящей
последовательности применяет функтор func и записывает результат впоследовательность, начинающуюся с итератора out.
• accimulate(It p, It q, T i, F func) - Последовательно применяет бинарный
функтор func к парам (i, *p++), где i - некоторое начальное значение, котороезатем каждый раз заменяется значением, которое возвращает функтор. Функтордолжен возвращать значение типа T.
http://www.slideshare.net/IgorShkulipa 29
Модифицирующие алгоритмы• sort(It p, It q), sort(It p, It q, Pr pred) - Сортирует элементы
последовательности в порядке возрастания.
• stable_sort(It p, It q), stable_sort(It p, It q, Pr pred) - Сортирует
элементы, сохраняя порядок элементов с одинаковыми значениями относительнодруг друга. Эти алгоритмы требуют итераторов произвольного доступа, поэтомуна списке работать не будут. Но у списка есть собственные функции члены sort,stable_sort.
• void nth_element(It p, It nth, It q), void nth_element(It p, It q, It
nth, Pr pred) - Позволяет получить n-й по порядку элемент (n-й по счету, как
если бы массив был отсортирован), переставляя элементы таким образом, чтовсе элементы до него меньше, либо равны ему, а элементы после - больше, либоравны ему.
• partition(It p, It q, Pr pred) - Переставляет элементы последовательности
таким образом, что все элементы, для которых предикат вернул true,предшествуют тем, для которых он вернул false. Возвращает итератор на первыйэлемент из второй группы.
• void partial_sort(It p, It middle, It q), void partial_sort(It p, It
middle, It q, Pr pred) - Переставляет элементы последовательности так, что
элементы межу итераторами p и q располагаются в том порядке, как если быпоследовательность была отсортирована, а элементы в оставшейся части - впроизвольном порядке. То есть получаем часть отсортированнойпоследовательности (не то же самое, что отсортированную часть).
• merge(It p, It q, Itr i, Itr j, Iter out), merge(It p, It q, Itr i, Itr
j, Iter out, Pr pred) - Сортирует две последовательности слиянием.
http://www.slideshare.net/IgorShkulipa 30
Лабораторная работа №2. Функторы, адаптеры, алгоритмы
Создать парсер командной строки, реализующий команды для работы состандартными алгоритмами.
Например:➢ sort 2 4 1 8 3 5 – сортирует заданный массив элементов
➢ sum 10 5 8 11 – сумма указанных чисел
➢ average 7 8 3 4 – среднее указанных чисел
➢ find 6 in 5 8 7 3 6 9 2 – находит номер указанного элемента
➢ и т.д. 10+ алгоритмов
Выполнить реализацию с использованием паттернов «Стратегия нафункторах» и «Адаптер».
Реализовать приложение на основе паттерна «Singleton».
Парсер команд удобно реализовывать на основе контейнеров «Очередь»или «Стек».