Объектно-Ориентированное Программирование на C++,...
-
Upload
dima-dzuba -
Category
Education
-
view
204 -
download
7
description
Transcript of Объектно-Ориентированное Программирование на C++,...
TEMPLATEО СПОСОБЕ НАПИСАНИЯ ПРОГРАММЫ, КОТОРАЯ ВЫПОЛНЯЕТСЯ ВНУТРИ КОМПИЛЯТОРА
Два вида многократного использования кода
Наследование
• Создаем структуру для работы с «базовым классом»
• Создаем классы-наследники на каждый случай.
Шаблоны
• Описываем «стратегию работы» с «неопределенным» классом.
• Компилятор в момент создание класса по шаблону, сам создает нужный «код» для конкретного класса.
TemplatesшаблоныПротечка абстракции: Неудобной составляющей работы с коллекциями объектов родительского типа является необходимость приведения родительского типа к типу-наследнику (для выполнения необходимых операций над элементом коллекции). Т.е. мы жертвуем статическим контролем типов.
Шаблон типа позволяет достаточно просто определить и реализовать без потерь в эффективности выполнения программы и, не отказываясь от статического контроля типов, любые виды коллекций.
Простой шаблонCPP_Examples14_Templatetemplate <class T> class Print
{
public:
Print(T value)
{
std::cout << "Value:" << value <<
std::endl;
};
};
Перед описанием класса ставим ключевое слово template <class T>
T – используем вместо имени класса, который будет заменяться при создании конкретного экземпляра класса.
Специализация шаблоновCPP_Examples14_TemplateSpecialization
template <class T>
class mycontainer {
// …
};
template <>
class mycontainer <char> {
// ..
};
Иногда бывает необходимость сделать специальную реализацию шаблона для какого-либо типа.
В этом случае, можно описать отдельную реализацию класса, дополнив его новыми методами или переопределив реализацию существующих.
Templatesдве модели1. Наиболее популярный подход - модель включения(inclusion model), определения шаблонов полностью размещаются в заголовочном файле.2. Модель явного инстанцирования (explicitinstantiation model), как правило реализуется директивой явного инстанцирования (explicitinstantiation directive).
Inclusion modeltemplate<class T> class stack {
T* v;
T* p;
int sz;
public:
stack(int s) { v = p = new T[sz=s]; }
~stack() { delete[] v; }
void push(T a) { *p++ = a; }
T pop() { return *--p; }
int size() const { return p-v; }
};
explicit instantiation modelCPP_Examples14_TemplateStacktemplate <class T> class
MyStack
{
public:
MyStack(void);
};
template <class T>
MyStack<T>::MyStack(void)
{
_size = 0;
_current = NULL;
}
template class MyStack<class
MyClass>;
Множественные параметры шаблонов и параметры-переменныеCPP_Examples14_MultiTemplate
template <class A, class B> class Sum
{
…
};
template <class A, int B> class Add
{
…
};
• Если нужно указать несколько классов/типов, то они указываются через запятую.
• Параметром шаблона может быть не только тип, но и значение переменной.
Шаблоны с переменным числом параметровCPP_Examples14_VariadicTemplatetemplate <class T> void print(const T& t) {
std::cout << t << std::endl;
}
template <class First, class... Rest> void
print(const First& first, const Rest&...
rest) {
print(rest...);
}
• В C++ есть возможность сделать шаблон с переменным числом параметров.
• В этом случае используется «…» для указания списка параметров.
• Работать с такими шаблонами можно по принципу рекурсии.
Множественное наследование в шаблонахCPP_Examples14_DecoratorTemplate
template <typename... BaseClasses>
class Printer : public BaseClasses... {
public:
Printer(BaseClasses&&... base_classes) :
BaseClasses(base_classes)...
{
}
};
Шаблоны в качестве параметров шаблоновCPP_Examples14_TemplateParameters
• Шаблон можно указать в качестве параметра шаблона!
• Все типы, которые используются при конструировании нового типа с помощью шаблона – должны быть его параметрами.
template <class T> class Payload
{
…
};
template <template <class> class PL, class T> class Printer
{
…
};
Printer<Payload, int> printer;
Большая «скучная» книга про шаблоны (но самая лучшая)
Год выпуска: 2002Автор: Андрей АлександрескуЖанр: Программирование [C++]Издательство: Издательский дом "Вильямс" Москва - Санкт-Петербург - КиевISBN: 5-8459-0351-3(рус), 0-201-77581-6(англ.)Количество страниц: 326Описание: В книге изложена новая технология программирования, представляющая собой сплав обобщённого программирования шаблонов и объектно - ориентированного программирования на С++. Обобщённые компоненты, созданные автором, высоко подняли уровень абстракции, наделив язык С++ чертами языка спецификации проектирования, сохранив всю его мощь и выразительностьВ книге изложены способы реализации основных шаблонов проектирования. Разные компоненты воплощены в библиотеке Loki, которую можно загрузить с Web-страницы автора. Книга предназначена для опытных программистов на С++
Перегрузка операций
Прежде чем начать• Это механизм, при неумелом использовании
которого можно полностью запутать код.
• Непонятный код – причина сложных ошибок!
• Перегруженные операции помогают определить «свойства» созданного вами класса, но не алгоритма работы с классами!
Перегрузка операцийМожно описать функции, для описания следующих операций:
+ - * / % ^ & | ~ !
= < > += -= *= /= %= ^= &=
|= << >> >>= <<= == != <= >= &&
|| ++ -- ->* , -> [] () new delete
Нельзя изменить приоритеты этих операций, равно как и синтаксические правила для выражений. Так, нельзя определить унарную операцию % , также как и бинарную операцию !.
Синтаксисtype operator operator-symbol ( parameter-list )
Ключевое слово operator позволяет перегружать операции. Например:
• Перегрузка унарных операторов:◦ ret-type operator op ( arg )
◦ где ret-type и op соответствуют описанию для функций-членов операторов, а arg — аргумент типа класса, с которым необходимо выполнить операцию.
• Перегрузка бинарных операторов◦ ret-type operator op( arg1, arg2 )
◦ где ret-type и op — элементы, описанные для функций операторов членов, а arg1 и arg2 —аргументы. Хотя бы один из аргументов должен принадлежать типу класса.
Префиксные и постфиксные операторы++ и --
Операторы инкремента и декремента относятся к особой категории, поскольку имеется два варианта каждого из них:
• преинкрементный и постинкрементный операторы;
• предекрементный и постдекрементный операторы.
При написании функций перегруженных операторов полезно реализовать отдельные версии для префиксной и постфиксной форм этих операторов. Для различения двух вариантов используется следующее правило: префиксная форма оператора объявляется точно так же, как и любой другой унарный оператор; в постфиксной форме принимается дополнительный аргумент типа int.
Пример:
friend Point& operator++( Point& ) // Prefix increment
friend Point& operator++( Point&, int ) // Postfix increment
friend Point& operator--( Point& ) // Prefix decrement
friend Point& operator--( Point&, int ) // Postfix decrement
ПримерCPP_Examples16
class Rectangle
{
private:
int _width, _height;
public:
Rectangle(int width,int height) :
_width(width),_height(height) {}
friend Rectangle
operator+(Rectangle,Rectangle);
Rectangle operator++(){
_width ++;_height++;return *this;}
int operator[](int i){
switch (i)
{
case 0: return _width;
case 1: return _height;
default:
throw exception_ptr();
break;
}
}
};
Переопределение оператора присваиванияCPP_Examples16_OperatorNew
Он должен быть нестатической функцией-членом. Никакой оператор operator= не может быть объявлен как функция, не являющаяся членом.
Он не наследуется производными классами.
Компилятор может создавать для типов классов функции operator= по умолчанию, если они не существуют. В этом случае оператор равно применяется к каждому члену класса.
Делаем функторCPP_Examples16_OperatorFunctor
Синтаксис: primary-expression ( expression-list )
В этом контексте основное-выражение является первым операндом, а список-выражений(список аргументов, который может быть пустым) — вторым. Оператор вызова функции используется для операций, для которых необходимо определенное количество параметров. Такой подход действует потому, что список-выражений представляет собой не отдельный операнд, а список. Оператор вызова функции должен представлять собой нестатическую функцию-член.
Перегрузка операторов new и deleteCPP_Examples16_OperatorConstructor
Операторы new и delete можно перегрузить. Для этого есть несколько причин:◦ Можно увеличить производительность за счёт кеширования: при удалении объекта не освобождать
память, а сохранять указатели на свободные блоки, используя их для вновь конструируемых объектов.
◦ Можно выделять память сразу под несколько объектов.
◦ Можно реализовать собственный "сборщик мусора" (garbage collector).
◦ Можно вести лог выделения/освобождения памяти.
Операторы new и delete имеют следующие сигнатуры:
void *operator new(size_t size);
void operator delete(void *p);
Оператор new принимает размер памяти, которую необходимо выделить, и возвращает указатель на выделенную память.
Оператор delete принимает указатель на память, которую нужно освободить.
Статические классы и члены классовCPP_Examples17
Класс - это тип, а не некоторое данное, и для каждого объекта класса создается своя копия атрибутов, представляющих данные. Однако, наиболее удачная реализация некоторых типов требует, чтобы все объекты этого типа имели некоторые общие атрибуты.
class task {
static void shedule(int); // метод класса
static task* chain; //атрибут класса
};
if (task::chain == 0) // какие-то операторы
Singleton◦ Описание задачи
В программе существуют глобальные объекты с одним экземпляром на всю программу.
◦ Описание решенияКласс объекта хранит ссылку на сам объект и может инициировать создание объекта как при первом обращении так и при старте программы.
◦ Когда применятьВсегда когда нужно хранить глобальные свойства системы или иметь доступ к глобальному ресурсу (если он может существовать только в одном экземпляре)
◦ ПримерНапример, при отправке сообщений в очередь мы хотим убедится что у нас не будет конфликтов из-за многопоточности. Поэтому мы создаем один объект по работе с данной очередью и вставляем в нем мониторы.
24
SingletonПреимущества◦ контролируемый доступ к единственному экземпляру.
◦ уменьшение числа имен, используемых в системе.
◦ допускает уточнение операций и представления.
◦ допускает переменное число экземпляров.
◦ большая гибкость, чем у операций класса.
Реализация◦ гарантирование единственного экземпляра.
◦ порождение подклассов Singleton (при необходимости).
25
mcSingletonДолжен остаться только один!
26
SingletonCPP_Examples18
class McLeod
{
private:
static McLeod* _instance;
McLeod(){
cout << "I am alive!\n";}
public:
static McLeod * GetInstance(){
if(_instance==NULL) _instance = new McLeod();
return _instance;}
void Print() { cout << "I am only one!\n";}
static void Die()
{
if(_instance!=NULL)
{
delete _instance;
_instance = NULL;
}
}
};
27