Re[3]: Method Address
От: diov  
Дата: 12.03.02 06:35
Оценка:
Здравствуйте diov, Вы писали:

D>Конечно, полученное решение далеко от совершенства, но оно работает. Вот во что это вылилось :


Начинаем в срочном порядке исправлять огрехи :


D>event_handler.h


D>template <class Hoster>

D>union TMethod
D>{

D>#define METHOD_ADDRESS(class_method) ((void *)(TMethod<CTest>(TMethod<CTest>::Ptr(class_method))))


Ошибка. Вместо этого должно было быть :
#define METHOD_ADDRESS(C, M) ((void *)(TMethod<C>(TMethod<C>::Ptr(M))))
и использовать надо бы так : METHOD_ADDRESS(CTest, MegaQ)

НО ! Все это не нужно теперь, поскольку оказалось возможным обойтись БЕЗ шаблонов.
Вот как должно быть :


//-------------------------------------------------------------------

class CEmpty {};

union UMethod
{
    typedef HRESULT (STDCALL CEmpty::*Ptr)();

    Ptr        pMethod;
    DWORD    dwAddress;
    void *    pVoid;

    inline UMethod() :
    pVoid(0)
    {}

    inline UMethod(Ptr method) :
    pMethod(method)
    {}

    inline operator DWORD () {
        return dwAddress;
    }

    inline operator void * () {
        return pVoid;
    }
};

// Macro for retrieving method address
// Example : METHOD_ADDRESS(CTest::MegaQ)
// Returns (void *)
#undef METHOD_ADDRESS
#define METHOD_ADDRESS(class_method) ((void *)(UMethod(UMethod::Ptr(class_method))))

//-------------------------------------------------------------------



D>class CEventHandler {


В этом классе — без изменений

D>event_handler.cpp


Тут тоже ничего не менялось...

D>main.cpp



#include <windows.h> // в прошлый раз эта строчка потерялась
#include "event_handler.h"

class CTest
{
private :
public :
    HRESULT STDCALL MegaQ(int a, int b, int * c) {
        * c = a + b;
        return S_OK;
    }
    HRESULT STDCALL MegaZ(char * psz, int b) {
        * psz = char(b);
        return S_OK;
    }
};
//-------------------------------------------------------------------

int main(int argc, char * argv[])
{
    CTest o;
    CEventHandler h1(& o, METHOD_ADDRESS(CTest::MegaQ));
    CEventHandler h2(& o, METHOD_ADDRESS(CTest::MegaZ));

    int n;
    h2.Raise(1, 2, & n);
    h2.Raise("ssss", 2);

    return 0;
}
//-------------------------------------------------------------------


D>Комментарии


D>Адрес метода получается 2мя способами — напрямую (для h1) и через макрос (для h2).

D>Передача события основана на __stdcall :
D>1) параметры в стек пихаются справа налево — this оказывается последним (esp + 4)
D>2) очистку стека делает вызывающая сторона
D>Это позволяет делать "слепое" делегирование. Более лучшее его описание ищите где то неподалеку.

Здесь следует добавить, что именно поэтому нельзя в параметрах использовать ссылки (int & n),
и не рекомендуется использовать const участки памяти.

D>Достоинства

D>1. "Слепое" делегирование позволяет передавать какие угодно параметры, т.е. подходит для всех случаев.
D>2. Простота в использовании.
D>3. Автоматическая проверка указателей на валидность при генерации события.

D>Недостатки

D>1. Появляется куча сгенеренных из шаблона TMethod классов.
Этот недостаток убран.
D>2. Замедлилась процедура установки обработчика : на вызов конструктора TMethod и вызов operator void * ().
D>3. Чууть замедлился вызов/делегирование события (но без этого никак).
D>4. Классы — обработчики обязаны для методов обработки ставить __stdcall.
D>5. Не поддерживается множественное наследование :-(((

D>P.S.

D>Если возникнет потребность, будет адаптировано для множественного наследования.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.