Александр Шаргин - Делегаты на C++

Тут можно читать онлайн Александр Шаргин - Делегаты на C++ - бесплатно полную версию книги (целиком) без сокращений. Жанр: comp-programming, издательство The RSDN Group, год 2003. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.

Александр Шаргин - Делегаты на C++ краткое содержание

Делегаты на C++ - описание и краткое содержание, автор Александр Шаргин, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Делегаты на C++ - читать онлайн бесплатно полную версию (весь текст целиком)

Делегаты на C++ - читать книгу онлайн бесплатно, автор Александр Шаргин
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

С точки зрения разбухания кода наиболее неблагополучно выглядит класс CDelegateX. Его специализация генерируется для каждой сигнатуры, для которой будет использоваться делегат. Но методы Add, Removeи RemoveAllникак не используют информацию о сигнатуре. То есть для этих методов каждый раз будет генерироваться один и тот же код. Чтобы изменить ситуацию, можно вынести реализацию этих методов в отдельный нешаблонный класс CDelegateImpl. Тогда все специализации шаблона IDelegateXунаследуют эту реализацию, и она останется в программе в единственном экземпляре.

Чтобы реализовать эту идею, для начала разобьём интерфейс IDelegateXна два интерфейса. Базовый, IComparableDelegate, будет "отвечать" за сравнение делегатов. Производный, уже знакомый нам IDelegateX, будет определять дополнительный метод Invoke.

class IComparableDelegate {

public:

virtual ~IComparableDelegate() {}

virtual bool Compare(IComparableDelegate* pDelegate) = 0;

};

template‹class TRet TEMPLATE_PARAMS›

class I_DELEGATE: public IComparableDelegate {

public:

virtual TRet Invoke(PARAMS) = 0;

};

Обратите внимание, что в интерфейсе IComparableDelegateшаблоны не используются. Теперь в терминах этого интерфейса можно реализовать базовый класс CDelegateImpl, который будет отвечать за поддержку списка делегатов. Соответственно, в нём будут реализованы методы Add, Removeи Invoke.

class CDelegateImpl {

public:

typedef std::list‹IComparableDelegate*› DelegateList;

CDelegateImpl(IComparableDelegate* pDelegate = NULL) { Add(pDelegate); }

~CDelegateImpl() { RemoveAll(); }

bool IsNull() { return (m_DelegateList.empty()); }

protected:

void Add(IComparableDelegate* pDelegate) {

if (pDelegate != NULL) m_DelegateList.push_back(pDelegate);

}

void Remove(IComparableDelegate* pDelegate) {

DelegateList::iterator it;

for (it = m_DelegateList.begin(); it != m_DelegateList.end(); ++it) {

if ((*it)-›Compare(pDelegate)) {

delete (*it);

m_DelegateList.erase(it);

break;

}

}

}

void RemoveAll() {

DelegateList::iterator it;

for (it = m_DelegateList.begin(); it != m_DelegateList.end(); ++it) delete (*it);

m_DelegateList.clear();

}

protected:

DelegateList m_DelegateList;

};

Теперь реализация класса CDelegateXсущественно упрощается. В нём останутся только операторы (для которых используется inline-подстановка) и метод Invoke. Только этот метод и будет сгенерирован отдельно для каждой специализации - хороший результат по сравнению с тем, что было раньше. Новая реализация класса CDelegateXбудет выглядеть так:

template‹class TRet TEMPLATE_PARAMS›

class C_DELEGATE: public CDelegateImpl {

public:

typedef I_DELEGATE‹TRet TEMPLATE_ARGS› IDelegate;

C_DELEGATE(IDelegate* pDelegate = NULL): CDelegateImpl(pDelegate) {}

C_DELEGATE‹TRet TEMPLATE_ARGS›& operator=(IDelegate* pDelegate) {

RemoveAll();

Add(pDelegate);

return *this;

}

C_DELEGATE‹TRet TEMPLATE_ARGS›& operator+=(IDelegate* pDelegate) {

Add(pDelegate);

return *this;

}

C_DELEGATE‹TRet TEMPLATE_ARGS›& operator-=(IDelegate* pDelegate) {

Remove(pDelegate);

return *this;

}

TRet operator()(PARAMS) {

return Invoke(ARGS);

}

private:

TRet Invoke(PARAMS) {

DelegateList::const_iterator it;

for (it = m_DelegateList.begin(); it!= --m_DelegateList.end(); ++it) static_cast‹IDelegate*› (*it)-›Invoke(ARGS);

return static_cast‹IDelegate*› (m_DelegateList.back())-›Invoke(ARGS);

}

};

Обратите внимание на появившиеся приведения типов. В данном случае они никак не сказываются на типобезопасности делегатов, так как в списке m_DelegateListмогут храниться только указатели на объекты классов CStaticDelegateXи CMethodDelegateX, а эти указатели заведомо приводятся к указателю на IDelegate.

В заключение несколько слов о проблеме производительности. Как уже говорилось, она может возникать из-за распределения объектов делегатов в куче. К сожалению, реализовать делегаты как стековые объекты не представляется возможным, так как для них существенным свойством является полиморфное поведение. Но и тут ситуацию можно существенно улучшить. Поскольку все делегаты централизованно создаются внутри функции NewDelegate, для них вполне возможно написать специализированный аллокатор, который будет распределять память для делегатов быстро и эффективно. Написание такого аллокатора оставляется читателю в качестве упражнения.

Заключение

Хочется отметить, что рассмотренный нами пример реализации делегатов может служить иллюстрацией как сильных, так и слабых сторон языка C++. Слабая сторона C++ - это его сложность. Особенно хорошо она заметна при реализации библиотек на базе шаблонов. Их код трудно читать и ещё труднее писать, так как в них семантическая сложность усугубляется сложностью синтаксической. Сильной же стороной C++ является совершенно невероятная гибкость этого языка. В рамках C++ можно реализовать и бесшовно интегрировать в язык самые разные возможности. Причём сделать это удаётся даже несмотря на грубейшие ошибки и недоработки разработчиков некоторых компиляторов.

Комментарии:

наследование операторов

›Дело в том, что в языке C++ операторы не наследуются.

Это не верно по крайней мере для MSVC++. Более того этот метод используется при написании функтора из библиотеки Loki http://fara.cs.uni-potsdam.de/~kaufmann/?page=lokiport(файл Functor.h), см. также http://www.geocities.com/rani_sharoni/LokiPort.html(VC7) и конечно оригинал http://moderncppdesign.com/

#include ‹stdio.h›

int main() {

struct base {

void operator()(int x) { printf("void base::operator()(%d)\n",x); }

};

struct derived: base {};

derived()(5);

return 0;

}

yaroslav_v 1.5.2003 9:55
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Александр Шаргин читать все книги автора по порядку

Александр Шаргин - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




Делегаты на C++ отзывы


Отзывы читателей о книге Делегаты на C++, автор: Александр Шаргин. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x