Колбек для метода класса.

Тема в разделе "LANGS.C", создана пользователем n0name, 10 мар 2007.

  1. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    Возникла одна проблемка.
    В методе класса мне нужно вызвать калбек.
    Объявляю метод:
    Код (Text):
    1. class CMyClass
    2. {    
    3. protected:
    4. ...  
    5.     virtual dword Callback1()
    6.     virtual dword AddOperator(TCallback Clb);
    7. ...
    8. private:
    9. ...
    10. public:
    11. ...
    12.     virtual dword Test();
    13.     virtual ~CMyClass();
    14. };
    Перед этим :
    typedef dword (* TCallback)();.
    В Test() делаю примерно следующее:
    Код (Text):
    1.     AddOperator(Callback1);
    Однако компилятор ругается :\
    ../source/CMyClass.cpp:224: error: argument of type `dword (MyNS::CMyClass::)()' does not match `dword (*)()'

    Пробовал через void *, однако Callback1 не приводится к нему.
    Что делать?
     
  2. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Я тоже так хотел сделать. С преобразованием типов я так и не добился ничего. Пришлось делать метод статическим, либо вообще выносить его за пределы класса (что тоже самое). А указатель на объект придется передать как-нибудь
     
  3. reverser

    reverser New Member

    Публикаций:
    0
    Регистрация:
    27 янв 2004
    Сообщения:
    615
    http://www.gamedev.ru/faq/?id=52
     
  4. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    Благодарю. Я пробовал (* CMyClass::Func), однако до (CMyClass::* Func) не допер.
     
  5. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    reverser
    хек, сенкс) не знал.
     
  6. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Для win32 самое распространённое - колбэк с параметром, представляющим собой указатель на объект. В колбэке (статическом методе класса или просто функции) параметр преобразуется к типу класса и вызывается уже обычный метод объекта).

    А вообще, std::mem_fun & K°, boost::mem_fn, boost::bind и т.п.
     
  7. dev_null

    dev_null New Member

    Публикаций:
    0
    Регистрация:
    23 мар 2007
    Сообщения:
    5
    по поводу приведения к void* : указатель на метод по крайней мере в Visual Studio занимает либо 4 либо 8 байт, в зависимости от того содержит ли класс виртуальные функции, причем sizeof() возвращает всегда 4 .... остальные бродят в стеке где-то недалеко, я полностью сам не разобрался.

    в любом случае прикастить его можно так:
    union Dummy
    {
    void (_cdecl YourClass_t::*method)(int param1,char param2); //твое объявление указателя на метод в стиле _cdecl или _stdcall
    void * pVoidPtr;
    } d;

    d.method=&YourClass_t::NameOfMethod; //для 2005 VS или d.method=YourClass_t::NameOfMethod для 2003

    всё в d.pVoidPtr - теперь указатель на метод .... можно и без union, объявляем структуру с одним указателем и кастим указатель на структуру к void* тоже сработает ...
    только вызвать его явно нельзя, чтоб прога не упала, потому что по умолчанию там используется соглашении thiscall и указаетль this идет через ecx

    поэтому этого мало и методы надо объявлять в духе _cdecl. т.е:

    YourClass_t
    {
    ...
    void _cdecl NameOfMethod(int param1,char param2);
    ...
    };

    а потом кастим void* к указателю на функцию, первым параметром кидаем указатель на объект (будущий this) и если повезло, и указаетль на на виртуальный метод - то всё сработает :)

    Это конечно изврат, то так меня занесло - из личного опыта ....


    код приведенный на http://www.gamedev.ru/faq/?id=52
    бдет работать для обычных классов но совсем не обязан в случае множественного наследования, либо когда в производном классе появляются виртуальные функции ... Это всё касается случая когда берется указатель на метод производного класса, а потом делается вызов метода через указатель базового класса
    в Visual Studio 2003 / 2005 есть опции компилера /vmm /vmv (можно в MSDN посмотреть) для множественного и виртуального наследования

    В случае когда надо вызвать произвольный метод произвольного класса помогают темпляты, вот например кусок кода с помощью которого можно хранить указатель на метод и сам класс, для вызова когда-нибудь (очень удобно для callback'ов разных)

    Код (Text):
    1. template <typename Real_t> class IFnCaller_t
    2. {
    3. public: virtual Real_t Call(const std::valarray<Real_t>& vals)=0;
    4.         virtual ~IFnCaller_t(){}
    5. };
    6.  
    7. template <typename Class_t,
    8. typename Real_t>
    9. class FnCaller_t : public IFnCaller_t<Real_t>
    10. {
    11. public:
    12.     FnCaller_t(Class_t* pClass,Real_t (Class_t::*pFn)(const std::valarray<Real_t>& vals)):
    13.       m_pClass(pClass),m_pFn(pFn){}
    14. protected:
    15.     virtual Real_t Call(const std::valarray<Real_t>& vals){return (m_pClass->*m_pFn)(vals);}
    16.     Class_t* m_pClass;
    17.     Real_t (Class_t::*m_pFn)(const std::valarray<Real_t>&);
    18. };
    19.  
    20. template <typename Class_t,typename Real_t>
    21. IFnCaller_t<Real_t>* FnCaller(Class_t* pObject,Real_t (Class_t::*pFn)(const std::valarray<Real_t>& vals))
    22. {return new FnCaller_t<Class_t,Real_t>(pObject,pFn);}
     
  8. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    dev_null

    union-ы это плохо. Вобще стандартег говорит что void* вместит любой указатель, кроме указателя на функцию. Поэтому такой обман компиллера это не хорошо.
     
  9. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    На счод статьи на гамдеве. Немного модифицировал пример (решил проверить выдвинутый тезис). У меня 8-ка падает на компиляции. А что у вас? :)

    Код (Text):
    1. #include <iostream>
    2.  
    3. class Test
    4. {
    5. public:
    6.     void foo()
    7.     {
    8.         std::cout << "Test::foo called" << std::endl;
    9.     }
    10. };
    11.  
    12. template <class T>
    13. void boo(T t)
    14. {
    15.     t();
    16. }
    17.  
    18. int main()
    19. {
    20.     typedef void (Test::* pToFunc)();
    21.  
    22.     pToFunc pt = &Test::foo;
    23.  
    24.     Test test;
    25.  
    26.     boo(test.*pt);
    27.  
    28.     return 0;
    29. }
     
  10. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    8-ки сейчас нет, 7.1 говорит следующее:
    wefvf.cpp(26): error C2784: 'void boo(T)' : could not deduce template argument for 'overloaded function type' from 'overloaded function type'
     
  11. dev_null

    dev_null New Member

    Публикаций:
    0
    Регистрация:
    23 мар 2007
    Сообщения:
    5
    Реально падает !!! Visual Studio 8 с SP1, причем красиво и с табличкой :), обязательно проверю на gcc и расскажу
     
  12. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    dev_null
    internal compiler error: in cxx_expand_expr, at cp/expr.c:114

    gcc version 3.4.2 (mingw-special)
     
  13. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
     
  14. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    А Comeau, как всегда, на высоте:

    Код (Text):
    1. line 26: error: a pointer to a bound function may only be used to
    2.           call the function
    3.         Wild Guess: You're calling a member function and forgot the ()'s
    4.       boo(test.*pt);
    5.                 ^
     
  15. dev_null

    dev_null New Member

    Публикаций:
    0
    Регистрация:
    23 мар 2007
    Сообщения:
    5
    gcc (GCC) 4.1.1 (Gentoo 4.1.1-r3) на amd64:

    test.cpp: In function 'void boo(T) [with T = void (Test::)()]':
    test.cpp:26: instantiated from here
    test.cpp:15: error: too few arguments to function

    и никаких internal compiler error - исправились
     
  16. Gordon

    Gordon New Member

    Публикаций:
    0
    Регистрация:
    21 апр 2005
    Сообщения:
    21
    Адрес:
    Russia
  17. xcode

    xcode Member

    Публикаций:
    0
    Регистрация:
    8 апр 2007
    Сообщения:
    105
    Может, это и не совсем то, но я в таких случаях предпочитаю пользоваться интерфейсами. Никаких проблем с указателями на методы классов, все красиво и наглядно.
     
  18. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    xcode
    В EnumWindows интерфейс не передашь :)
     
  19. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    А всё-таки, получается, что нельзя никак передать указатель на функцию (нестатическую)? Или я что-то недопонял и такой прием существует?
     
  20. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    maxdiver
    Ссылка в посте N3.