Вход/Регистрация
Делегаты на C++
вернуться

Шаргин Александр

Шрифт:

Чтобы разрешить эту неоднозначность, придётся ввести дополнительный параметр функции NewDelegate, по которому и будет выбираться нужная версия функции:

// Параметр этого типа будет индикатором

template‹int use›

class UseVoid {};

…

template‹class TRet TEMPLATE_PARAMS›

I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TRet (*pFunc)(PARAMS), UseVoid‹0›) {

 return new C_STATIC_DELEGATE‹TRet TEMPLATE_ARGS›(pFunc);

}

template‹class TRet TEMPLATE_PARAMS›

I_DELEGATE‹TRet TEMPLATE_ARGS›* NewDelegate(TRet (*pFunc)(PARAMS), UseVoid‹1›) {

 return new C_STATIC_DELEGATE_VOID‹TRet TEMPLATE_ARGS›(pFunc);

}

Тем самым мы избавляемся от неоднозначности. Но возникает другая проблема. Теперь при вызове NewDelegate необходимо явно указывать, какая версия функции нам нужна:

void f;

int g;

…

NewDelegate(f, UseVoid‹1›);

NewDelegate(g, UseVoid‹0›);

Чтобы избавиться от необходимости явно указывать параметр UseVoid, напишем третий вариант функции NewDelegate, который будет автоматически (причём на этапе компиляции) определять и вызывать нужную версию этой функции. Для реализации этой идеи нам потребуется механизм преобразования типа TRet в константу 1 (в случае TRet=void) или 0 (для всех остальных типов). Мы уже решали аналогичную задачу в классе DelegateRetVal, поэтому теперь решение записывается без труда:

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). Поскольку на создание объектов в куче тратится гораздо больше времени, чем на создание стековых объектов, это может привести к проблемам производительности. В этом разделе мы рассмотрим некоторые пути преодоления этих проблем.

  • Читать дальше
  • 1
  • ...
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: