Возникла одна проблемка. В методе класса мне нужно вызвать калбек. Объявляю метод: Код (Text): class CMyClass { protected: ... virtual dword Callback1() virtual dword AddOperator(TCallback Clb); ... private: ... public: ... virtual dword Test(); virtual ~CMyClass(); }; Перед этим : typedef dword (* TCallback)();. В Test() делаю примерно следующее: Код (Text): AddOperator(Callback1); Однако компилятор ругается :\ ../source/CMyClass.cpp:224: error: argument of type `dword (MyNS::CMyClass:()' does not match `dword (*)()' Пробовал через void *, однако Callback1 не приводится к нему. Что делать?
Я тоже так хотел сделать. С преобразованием типов я так и не добился ничего. Пришлось делать метод статическим, либо вообще выносить его за пределы класса (что тоже самое). А указатель на объект придется передать как-нибудь
Для win32 самое распространённое - колбэк с параметром, представляющим собой указатель на объект. В колбэке (статическом методе класса или просто функции) параметр преобразуется к типу класса и вызывается уже обычный метод объекта). А вообще, std::mem_fun & K°, boost::mem_fn, boost::bind и т.п.
по поводу приведения к 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): template <typename Real_t> class IFnCaller_t { public: virtual Real_t Call(const std::valarray<Real_t>& vals)=0; virtual ~IFnCaller_t(){} }; template <typename Class_t, typename Real_t> class FnCaller_t : public IFnCaller_t<Real_t> { public: FnCaller_t(Class_t* pClass,Real_t (Class_t::*pFn)(const std::valarray<Real_t>& vals)): m_pClass(pClass),m_pFn(pFn){} protected: virtual Real_t Call(const std::valarray<Real_t>& vals){return (m_pClass->*m_pFn)(vals);} Class_t* m_pClass; Real_t (Class_t::*m_pFn)(const std::valarray<Real_t>&); }; template <typename Class_t,typename Real_t> IFnCaller_t<Real_t>* FnCaller(Class_t* pObject,Real_t (Class_t::*pFn)(const std::valarray<Real_t>& vals)) {return new FnCaller_t<Class_t,Real_t>(pObject,pFn);}
dev_null union-ы это плохо. Вобще стандартег говорит что void* вместит любой указатель, кроме указателя на функцию. Поэтому такой обман компиллера это не хорошо.
На счод статьи на гамдеве. Немного модифицировал пример (решил проверить выдвинутый тезис). У меня 8-ка падает на компиляции. А что у вас? Код (Text): #include <iostream> class Test { public: void foo() { std::cout << "Test::foo called" << std::endl; } }; template <class T> void boo(T t) { t(); } int main() { typedef void (Test::* pToFunc)(); pToFunc pt = &Test::foo; Test test; boo(test.*pt); return 0; }
8-ки сейчас нет, 7.1 говорит следующее: wefvf.cpp(26): error C2784: 'void boo(T)' : could not deduce template argument for 'overloaded function type' from 'overloaded function type'
Реально падает !!! Visual Studio 8 с SP1, причем красиво и с табличкой , обязательно проверю на gcc и расскажу
dev_null internal compiler error: in cxx_expand_expr, at cp/expr.c:114 gcc version 3.4.2 (mingw-special)
А Comeau, как всегда, на высоте: Код (Text): line 26: error: a pointer to a bound function may only be used to call the function Wild Guess: You're calling a member function and forgot the ()'s boo(test.*pt); ^
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 - исправились
Может, это и не совсем то, но я в таких случаях предпочитаю пользоваться интерфейсами. Никаких проблем с указателями на методы классов, все красиво и наглядно.
А всё-таки, получается, что нельзя никак передать указатель на функцию (нестатическую)? Или я что-то недопонял и такой прием существует?