Делегаты на C++ - [6]
>template‹class T›
>struct IsVoid {
> enum {> Result = 0};
>};
>template‹› struct
>IsVoid‹void› {
> enum {Result = 1};
>};
Теперь воспользуемся классом IsVoid для выбора нужного варианта функции NewDelegate.
>template‹class TRet TEMPLATE_PARAMS›
>I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TRet (*pFunc)(PARAMS)) {
> return NewDelegate(pFunc, UseVoid‹IsVoid‹TRet›::Result›());
>}
Аналогичным образом NewDelegate перегружается для случая создания объектов CMethodDelegate*:
>I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TObj* pObj, TRet (TObj::*pMethod)(PARAMS), UseVoid‹0›) {
> return new C_METHOD_DELEGATE‹TObj, TRet TEMPLATE_ARGS› (pObj, pMethod);
>}
>template ‹class TObj, class TRet TEMPLATE_PARAMS›
>I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TObj* pObj, TRet (TObj::*pMethod)(PARAMS), UseVoid‹1›) {
> return new C_METHOD_DELEGATE_VOID‹TObj, TRet TEMPLATE_ARGS› (pObj, pMethod);
>}
>template ‹class TObj, class TRet TEMPLATE_PARAMS›
>I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TObj* pObj, TRet (TObj::*pMethod)(PARAMS)) {
> return NewDelegate(pObj, pMethod, UseVoid‹IsVoid‹TRet›::Result›());
>}
Если вас успели утомить эти "хождения по мукам", у меня есть для вас хорошая новость. Проблема, которую мы только что решили, была последней. Осталось заменить возвращаемые значения методов Invoke и operator() в классе CDelegate на DelegateRetVal‹TRet›::Type, чтобы получить законченную реализацию делегатов для Visual C++ 6.0.
Полную версию реализации делегатов для Visual C++ 6.0 можно найти на сопровождающем компакт-диске.
Больше, лучше, быстрее
Реализация делегатов, которую мы рассмотрели выше, вполне работоспособна. Тем не менее, некоторые её особенности вызывают озабоченность. Во-первых, интенсивное использование шаблонов может привести к чрезмерному разбуханию кода. Во-вторых, объекты делегатов распределяются динамически (при помощи оператора new). Поскольку на создание объектов в куче тратится гораздо больше времени, чем на создание стековых объектов, это может привести к проблемам производительности. В этом разделе мы рассмотрим некоторые пути преодоления этих проблем.
С точки зрения разбухания кода наиболее неблагополучно выглядит класс 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;
JavaScript еще никогда не был так прост! Вы узнаете все возможности языка программирования без общих фраз и неясных терминов. Подробные примеры, иллюстрации и схемы будут понятны даже новичку. Легкая подача информации и живой юмор автора превратят нудное заучивание в занимательную практику по написанию кода. Дойдя до последней главы, вы настолько прокачаете свои навыки, что сможете решить практически любую задачу, будь то простое перемещение элементов на странице или даже собственная браузерная игра.
В этой книге автор, сам прошедший путь от разработчика до менеджера в сфере IT, рассказывает неочевидные моменты, которые являются критически важными для правильного управления. Почему разработчики увольняются после повышения зарплаты? Как делать FixedPrice проекты? Почему Scrum не упрощает менеджмент? Книга содержит ответ на эти и многие другие вопросы. В книге есть много баек, которые показывают тяжёлую, но интересную жизнь менеджера в разработке. Иллюстратор обложки: Ксения Ерощенко. Иллюстрации в тексте книги авторские.
Что такое ГЕЙМДИЗАЙН? Это не код, графика или звук. Это не создание персонажей или раскрашивание игрового поля. Геймдизайн – это симулятор мечты, набор правил, благодаря которым игра оживает. Как создать игру, которую полюбят, от которой не смогут оторваться? Знаменитый геймдизайнер Тайнан Сильвестр на примере кейсов из самых популярных игр рассказывает как объединить эмоции и впечатления, игровую механику и мотивацию игроков. Познакомитесь с принципами дизайна, которыми пользуются ведущие студии мира! Создайте игровую механику, вызывающую эмоции и обеспечивающую разнообразие.
Эта книга предназначена для всех, кто желает освоить СУБД MySQL. Для ее чтения вам не нужны никакие специальные знания – достаточно быть пользователем Windows. Вы узнаете, как установить и запустить MySQL, как создать собственную базу данных, как работать с данными при помощи команд SQL, как администрировать базу данных и оптимизировать ее работу. Разработчики веб-приложений на языках PHP, Perl и Java найдут в этой книге полезные сведения по использованию базы данных MySQL в соответствующих приложениях.
РАССЫЛКА ЯВЛЯЕТСЯ ЧАСТЬЮ ПРОЕКТА RSDN, НА САЙТЕ КОТОРОГО ВСЕГДА МОЖНО НАЙТИ ВСЮ НЕОБХОДИМУЮ РАЗРАБОТЧИКУ ИНФОРМАЦИЮ, СТАТЬИ, ФОРУМЫ, РЕСУРСЫ, ПОЛНЫЙ АРХИВ ПРЕДЫДУЩИХ ВЫПУСКОВ РАССЫЛКИ И МНОГОЕ ДРУГОЕ.