Делегаты на C++ - [3]

Шрифт
Интервал

>m_pFunc = pFunc; }

> virtual TRet Invoke(TP1 p1) { return m_pFunc(p1); }

> virtual bool Compare(IDelegate1‹TRet, TP1›* pDelegate) {

>  CStaticDelegate1‹TRet, TP1›* pStaticDel = dynamic_cast‹CStaticDelegate1‹TRet, TP1›* ›(pDelegate);

>  if (pStaticDel == NULL || pStaticDel-›m_pFunc != m_pFunc) return false;

>  return true;

> }

>private:

> PFunc m_pFunc;

>};


Как видим, мы вынуждены постоянно "таскать" за собой список параметров шаблона ‹TRet, TP1›. Для делегата с 10-ю параметрами эти списки полностью загромоздят код. Кроме того, вручную дублировать практически идентичные классы 11 раз - не самая удачная идея. Чтобы избежать лишнего дублирования кода, прибегнем к самому сильнодействующему (и самому опасному) средству языка C++ - препроцессору. Идея состоит в том, чтобы обозначить различающиеся участки кода в реализации классов CDelegateX макросами. Эти различающиеся участки можно разделить на 4 типа:

• Параметры шаблонов (например, ‹…, class TP1, class TP2, class TP3›). Список параметров шаблона обозначим макросом TEMPLATE_PARAMS.

• Аргументы шаблонов (например, ‹…, TP1, TP2, TP3›). Список аргументов шаблона обозначим макросом TEMPLATE_ARGS.

• Параметры функции Invoke (например, (TP1 p1, TP2 p2, TP3 p3)). Список этих параметров обозначим макросом PARAMS.

• Аргументы функции Invoke (например, (p1, p2, p3)). Список этих аргументов обозначим макросом ARGS.

Кроме этих макросов, нам потребуется макрос SUFFIX, который принимает значения от 0 до 10 и дописывается к именам классов следующим образом:

>#define COMBINE(a,b) COMBINE1(a,b)

>#define COMBINE1(a,b) a##b


>#define I_DELEGATE COMBINE(IDelegate, SUFFIX)

>#define C_STATIC_DELEGATE COMBINE(CStaticDelegate, SUFFIX)

>#define C_METHOD_DELEGATE COMBINE(CMethodDelegate, SUFFIX)

>#define C_DELEGATE COMBINE(CDelegate, SUFFIX)


ПРИМЕЧАНИЕ Обратите внимание на использование вспомогательного макроса COMBINE1. Если напрямую реализовать макрос COMBINE как #define COMBINE(a,b) a##b, то результатом подстановки COMBINE(IDelegate, SUFFIX) будет "IDelegateSUFFIX". А это совсем не то, что мы хотим получить. Поэтому использование COMBINE1 в данном случае необходимо.

Окончательная версия делегата, обобщённая с помощью всех этих макросов, будет выглядеть так:

>template‹class TRet TEMPLATE_PARAMS›

>class I_DELEGATE {

>public:

> virtual ~I_DELEGATE() {}

> virtual TRet Invoke(PARAMS) = 0;

> virtual bool Compare(I_DELEGATE‹TRet TEMPLATE_ARGS›* pDelegate) = 0;

>};


>template‹class TRet TEMPLATE_PARAMS›

>class C_STATIC_DELEGATE: public I_DELEGATE‹TRet TEMPLATE_ARGS› {

>public:

> typedef TRet (*PFunc)(PARAMS);

> C_STATIC_DELEGATE(PFunc pFunc) { m_pFunc = pFunc; }

> virtual TRet Invoke(PARAMS) { return m_pFunc(ARGS); }

> virtual bool Compare(I_DELEGATE‹TRet TEMPLATE_ARGS›* pDelegate) {

>  C_STATIC_DELEGATE‹TRet TEMPLATE_ARGS›* pStaticDel = dynamic_cast‹C_STATIC_DELEGATE‹TRet TEMPLATE_ARGS›*›(pDelegate);

>  if (pStaticDel == NULL || pStaticDel-›m_pFunc != m_pFunc) return false;

>  return true;

> }

>private:

> PFunc m_pFunc;

>};


>template‹class TObj, class TRet TEMPLATE_PARAMS›

>class C_METHOD_DELEGATE: public I_DELEGATE‹TRet TEMPLATE_ARGS› {

>public:

> typedef TRet (TObj::*PMethod)(PARAMS);

> C_METHOD_DELEGATE(TObj* pObj, PMethod pMethod) {

>  m_pObj = pObj;

>  m_pMethod = pMethod;

> }

> virtual TRet Invoke(PARAMS) { return (m_pObj-›*m_pMethod)(ARGS); }

> virtual bool Compare(I_DELEGATE‹TRet TEMPLATE_ARGS›* pDelegate) {

>  C_METHOD_DELEGATE‹TObj, TRet TEMPLATE_ARGS›* pMethodDel = dynamic_cast‹C_METHOD_DELEGATE‹TObj, TRet TEMPLATE_ARGS›*›(pDelegate);

>  if (pMethodDel == NULL || pMethodDel-›m_pObj != m_pObj || pMethodDel-›m_pMethod != m_pMethod) { return false; }

>  return true;

> }

>private:

> TObj *m_pObj;

> PMethod m_pMethod;

>};


>template‹class TRet TEMPLATE_PARAMS›

>I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TRet (*pFunc)(PARAMS)) {

> return new C_STATIC_DELEGATE‹TRet TEMPLATE_ARGS›(pFunc);

>}


>template ‹class TObj, class TRet TEMPLATE_PARAMS›

>I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TObj* pObj, TRet (TObj::*pMethod)(PARAMS)) {

> return new C_METHOD_DELEGATE‹TObj, TRet TEMPLATE_ARGS› (pObj, pMethod);

>}


>template‹class TRet TEMPLATE_PARAMS›

>class C_DELEGATE {

>public:

> typedef I_DELEGATE‹TRet TEMPLATE_ARGS› IDelegate;

> typedef std::list‹IDelegate*› DelegateList;

> C_DELEGATE(IDelegate* pDelegate = NULL) { >Add(pDelegate); }

> ~C_DELEGATE() { RemoveAll(); }

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

> 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:

> void Add(IDelegate* pDelegate) {

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

> }

> void Remove(IDelegate* 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() {


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Геймдизайн. Рецепты успеха лучших компьютерных игр от Super Mario и Doom до Assassin’s Creed и дальше

Что такое ГЕЙМДИЗАЙН? Это не код, графика или звук. Это не создание персонажей или раскрашивание игрового поля. Геймдизайн – это симулятор мечты, набор правил, благодаря которым игра оживает. Как создать игру, которую полюбят, от которой не смогут оторваться? Знаменитый геймдизайнер Тайнан Сильвестр на примере кейсов из самых популярных игр рассказывает как объединить эмоции и впечатления, игровую механику и мотивацию игроков. Познакомитесь с принципами дизайна, которыми пользуются ведущие студии мира! Создайте игровую механику, вызывающую эмоции и обеспечивающую разнообразие.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


MFC и OpenGL

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.