LibKing » Книги » comp-programming » Александр Шаргин - Делегаты на C++

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

Тут можно читать онлайн Александр Шаргин - Делегаты на C++ - бесплатно полную версию книги (целиком). Жанр: comp-programming, издательство The RSDN Group, год 2003. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте LibKing.Ru (ЛибКинг) или прочесть краткое содержание, предисловие (аннотацию), описание и ознакомиться с отзывами (комментариями) о произведении.
Александр Шаргин - Делегаты на C++
  • Название:
    Делегаты на C++
  • Автор:
  • Жанр:
  • Издательство:
    The RSDN Group
  • Год:
    2003
  • ISBN:
    нет данных
  • Рейтинг:
    3.8/5. Голосов: 101
  • Избранное:
    Добавить в избранное
  • Ваша оценка:

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

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

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

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

Шрифт:

Сбросить

Интервал:

Закладка:

Сделать

Второй путь - изменить функции Invokeтак, чтобы в случае TRet=voidони возвращали не void, а какое-нибудь нейтральное значение (например, ноль). Конечно, это не совсем честное решение, но оно вполне работоспособно. Посмотрим, как его можно реализовать.

В первую очередь нам нужен инструмент для преобразования типов, который на этапе компиляции превращал бы voidв int, а остальные типы оставлял бы без изменений. В C++ такие преобразования типов осуществляются с использованием полной специализации шаблонов (к счастью, её VC6 поддерживает). В нашем случае реализация будет выглядеть так.

template‹class T›

struct DelegateRetVal {

typedef T Type;

};

template‹›

struct DelegateRetVal‹void› {

typedef int Type;

};

Как видим, внутри класса DelegateRetValопределяется тип Type, который в общем случае совпадает с параметром шаблона T. Для случая T=voidэто поведение переопределяется с использованием специализации: в этом случае тип Typeопределяется как int. В результате, выражение DelegateRetVal‹TRet›::Typeбудет на этапе компиляции принимать нужный нам тип при любых значениях TRet.Следующий шаг - модификация классов CStaticDelegateXи CMethodDelegateX. Во-первых, нужно заменить значение, возвращаемое методом Invoke, на DelegateRetVal‹TRet›::Type. Во-вторых, нужно реализовать два дополнительных класса, CStaticDelegateVoidXи CMethodDelegateVoidX, для обработки случая TRet=void. Единственным их отличием от одноимённых классов без суффикса "Void" будет другая реализация метода Invoke:

#define C_STATIC_DELEGATE_VOID COMBINE(CStaticDelegateVoid, SUFFIX)

#define C_METHOD_DELEGATE_VOID COMBINE(CMethodDelegateVoid, SUFFIX)

template‹class TRet TEMPLATE_PARAMS›

class C_STATIC_DELEGATE_VOID: public I_DELEGATE‹TRet TEMPLATE_ARGS› {

virtual DelegateRetVal‹TRet›::Type Invoke(PARAMS) {

m_pFunc(ARGS);

return 0;

}

};

template‹class TObj, class TRet TEMPLATE_PARAMS›

class C_METHOD_DELEGATE_VOID: public I_DELEGATE‹TRet TEMPLATE_ARGS› {

virtual DelegateRetVal‹TRet›::Type Invoke(PARAMS) {

(m_pObj-›*m_pMethod)(ARGS);

return 0;}

};

ПРИМЕЧАНИЕВ этом месте может возникнуть соблазн избежать дублирования кода, породив класс CStaticDelegateVoidXот CStaticDelegateXи CMethodDelegateVoidXот CMethodDelegateXсоответственно. К сожалению, это не будет работать. Хотя мы и переопределяем виртуальный метод Invokeв производных классах, теоретическая возможность обратиться к Invokeбазовых классов сохраняется. Поэтому компилятор честно попытается сгенерировать их реализацию. А это в случае TRet=voidв очередной раз приведёт к ошибке, которую мы пытаемся обойти. Поэтому дублирование кода в данном случае неизбежно.

Осталось сделать последний шаг - перегрузить функцию NewDelegateещё двумя реализациями:

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 TRet TEMPLATE_PARAMS›

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

return new C_STATIC_DELEGATE_VOID‹void TEMPLATE_ARGS›(pFunc);

}

// Аналогично для CMethodDelegate*

В этом месте нас поджидает ещё один сюрприз. В большинстве случаев этот код будет работать, как по маслу. Но при задании TRet=voidвозникнет неоднозначность при обращении к функции NewDelegate. Правила разрешения перегрузки шаблонов функций описаны в разделе 14.5.5.2 Стандарта языка C++. В соответствии с этими правилами вторая версия NewDelegateне считается более специализированной, чем первая, так как для вызова обоих вариантов функции не требуется неявных преобразований типа.

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

Читать дальше
Тёмная тема

Шрифт:

Сбросить

Интервал:

Закладка:

Сделать


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

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




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


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


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

Напишите свой комментарий
Большинство книг на сайте опубликовано легально на правах партнёрской программы ЛитРес. Если Ваша книга была опубликована с нарушениями авторских прав, пожалуйста, направьте Вашу жалобу на PGEgaHJlZj0ibWFpbHRvOmFidXNlQGxpYmtpbmcucnUiIHJlbD0ibm9mb2xsb3ciPmFidXNlQGxpYmtpbmcucnU8L2E+ или заполните форму обратной связи.
img img img img img