Делегаты на C++ | страница 13
> 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, для них вполне возможно написать специализированный аллокатор, который будет распределять память для делегатов быстро и эффективно. Написание такого аллокатора оставляется читателю в качестве упражнения.
Заключение