Skip to main content
gamedev.net
🔒 Locked

[c++] Passing member function pointer

Started by directNoob Aug 31, 2006 at 5:30 PM 7 replies 1.7k views
Original Post
directNoob
directNoob
Hello. How can I use a member function pointer in a function. For example as a thread proc or a dialog proc? I tried the something like this:

...
_beginthread(MemberFunction, 0, NULL ) ;
...

But the compiler suggests

_beginthread(&MemberFunction, 0, NULL ) ;

But this also doesn´t work. I had a solution to that, but unfortunately I have forgotten where it was. Please help me! I need to use the member variables in the thread. Thanks Alex
rip-off
rip-off
A member function is unlike a normal function, it needs a "this" parameter. A virtual member function is different again. Member function pointers can be much larger than standard pointers, and have unique syntax rules. See here.
JohnBolton
JohnBolton
You cannot pass a non-static member function. The function must be a static member function or a non-member function.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
jflanglois
jflanglois
If you want to be able to use member functions with threads, you can take a look at Boost.Threads with boost::bind(). Boost.Threads promotes safer multithreading practices anyway.


jfl.
jflanglois
jflanglois
Another way consists of passing the instance as the parameter to the callback:

struct Test {  void DoStuff() {}};void DoStuffProxy( void * test ) {  reinterpret_cast< Test * >( test )->DoStuff();}int main() {  Test test;  _beginthread( &DoStuffProxy, 0, &test );}


It's really ugly and requires a proxy function, though. Contrast that with:

struct Test {  void DoStuff() {}};int main() {  Test test;  boost::thread t( boost::bind( &Test::DoStuff, &test ) );}



jfl.
dmail
dmail
If you don't want boost as a dependancy (like I did not)than have a look at the following as use as you wish.
NB I have not edited this from my project so there are defines and such that you don't need or know about.
*=============================================================================Devine Engine.(DE)-------------------------------------------------------------------------------DE_threads_common.hFile description:remarks:These thread starters could take multiple parameters, if a type list as descirbedby Andrei Alexandrescu (Modern C++ Design: Generic Programming and Design Patterns Applied) was used.author: Liam Devine    date: 25/07/2006=============================================================================*/#ifndef DE_THREADS_COMMON_H_#	define DE_THREADS_COMMON_H_#	include "../DE_plugin/DE_plugin_config.h"#	include "../DE_common/DE_exception.h"#	if	(DE_THREAD == DE_POSIX && defined(_MSC_VER))#		pragma comment(lib, "pthreadVC2.lib")#	endif//DE_THREAD == DE_POSIX && defined(_MSC_VER)#	if(DE_THREAD == DE_POSIX)#		define DE_THREAD_RETURN_TYPE void*#	elif(DE_THREAD == DE_WIN32)#		define DE_THREAD_RETURN_TYPE unsigned long __stdcall #	endif//DE_THREADnamespace DE{	namespace THREAD_STATERS	{ 		//normal C style fuction cross platform		typedef void* (*func_ptr) (void*);/*=============================================================================Struct : OPRemarks : Used to pass an object pointer of type(T) and a parameter pointer of type(P). These two members have to be pointers as it is dealing with different threads.-------------------------------------------------------------------------------=============================================================================*/		template<typename TYPE,typename PARAM>		struct OP		{			TYPE o;			PARAM p;			OP(TYPE T,PARAM P):o(T),p(P){}			OP(OP<TYPE,PARAM> const& op):o(op.o),p(op.p){}		};		//starts class member function which takes ONE parameter		template<typename RETURN,class TYPE,typename PARAM, RETURN (TYPE::*FUNC)(PARAM)>		DE_THREAD_RETURN_TYPE thread_starter(void* op)		{			//cast, dereference and pass to constructor			OP<TYPE*,PARAM> _op( * reinterpret_cast< OP<TYPE*,PARAM>* >(op) );			//delete the struct, as we have taken ownership of the pointer			//which was created in Thread.			delete (op);			(_op.o->*FUNC)(_op.p);//call the class member function passing the parameter			return 0;		}				//starts class member function with no parameter		template<typename RETURN, class TYPE, RETURN (TYPE::*FUNC)(void)>		DE_THREAD_RETURN_TYPE thread_starter(void* o)		{			(reinterpret_cast<TYPE*>(o)->*FUNC)();			return 0;		}	}//endof namespace THREAD_STARTERS}//endof namespace DE#endif//DE_THREADS_COMMON_H_


*=============================================================================Devine Engine.(DE)-------------------------------------------------------------------------------DE_win32_thread.hFile description:C++ thread wrapper for Window's thread.remarks:Has the abilty to pass an object member function as the start thread.Currently this is limited to a member function which takes void or an a pointerto an integral or a defined type. It could be developed further to use a type list as described by Andrei Alexandrescu in Modern C++ Design: Generic Programming and Design Patterns Applied. If either the return type or the parameter of the member function is void (NOTE: void* is different and just wrecks the type safety of the functions) then just omit that function template parameter. Obviously if there is no parameter for the member function then the start function does not expect to be passed a second paremeter.Example.....extern DE::Thread* thread;class E{public:void func( void);void func(char*);int func(int*);....};E* class_p = new E;char* char_p = new char('A');int* int_p = new int(1);//call void e::func voidthread->start<E,E::func>(class_p);/call void E::func char*thread->start<E,E::func,char*>(class_p,char_p);thread->start<int,E,E::func,int*>(class_p,int_p);...author: Liam Devine    date: 26/07/2006=============================================================================*/#ifndef DE_WIN_THREAD_H_#	define DE_WIN_THREAD_H_#	include "../DE_plugin/DE_plugin_config.h"#	include "DE_threads_common.h"#	if	(DE_THREAD == DE_WIN32)#		include <windows.h>#		include "../DE_plugin/DE_plugin_errors.h"namespace DE{class Thread{public:	Thread()	{		m_stack_size =  4096;		m_id = 0;	}	~Thread(void)	{		TerminateThread(m_handle, m_exit_code);	}	void start(THREAD_STATERS::func_ptr func, void* data)	{		m_handle =  CreateThread(NULL, m_stack_size,						reinterpret_cast<LPTHREAD_START_ROUTINE>(func),data,0,&m_id);		if(!m_handle)throw ( Thread_exception("failed to create thread") );	}		template<typename R, class C, typename P, R (C::*F)(P)>	void start(C *object, P param)	{		using namespace THREAD_STATERS;		//this struct is dynamically created here but we pass ownership to the thread_starter	 	OP<C*,P>* op = new OP<C*,P>(object,param);				m_handle = CreateThread(NULL, m_stack_size,(thread_starter<R,C,P,F>),					 static_cast<void*>(op), 0, &m_id);		if(!m_handle)throw ( Thread_exception("failed to create thread") );	}	template<typename R, class C, R (C::*F)(void)>	void start(C *object)	{		m_handle = CreateThread(NULL, m_stack_size,								(THREAD_STATERS::thread_starter<R,C,F>),								static_cast<void*>(object), 0, &m_id);		if(!m_handle)throw ( Thread_exception("failed to create thread") );	}	template<class C, typename P, void (C::*F)(P)>	void start(C *object, P param){ start<void,C,P,F>(object,param); }		template<class C,void (C::*F)(void)>	void start(C *object){ start<void,C,F>(object); }	void join(void)	{ 		DWORD res = WaitForSingleObject(m_handle,INFINITE);		switch(res)		{			case WAIT_OBJECT_0:return;// The thread got the handle			case WAIT_TIMEOUT: throw(Thread_exception("Cannot get mutex ownership due to time-out.")); 			case WAIT_ABANDONED:			{				//SYSTEM_LOG("Previous owner left the handle abandoned, system had to release it on the owner's behalf.");				return;//we will take this as a get			}				case WAIT_FAILED:			{				throw DE::Thread_exception(Win_error());			}		}	}		//returns the thread id of the thread which was started by this class	unsigned long thread_id(void){ return m_id; }	//returns the thread id of the thread which is calling this function	static unsigned long self(){ return( GetCurrentThreadId() ) ;}private:	DWORD m_id;	HANDLE m_handle;	DWORD m_stack_size, m_exit_code;};}//endof namespace DE#	endif//DE_THREAD == DE_WIN32#endif//DE_WIN_THREAD_H_
directNoob
directNoob
Wow, thanks for the massive response!
I will look through everything, later in the day.
@dmail:
This looks a bit complicated to my to just create a thread...
Maybe it gets clearer to me when I will habe looked over it more precisely.
From where did you get a solution like this?

For now.
Thanks to all.

Alex

dmail
dmail
Quote:
This looks a bit complicated to my to just create a thread...
Maybe it gets clearer to me when I will habe looked over it more precisely.


Well what I shown is more than just a method to start a thread it is also a light weight C++ wrapper for win32 threads, which really you only are interested in the Thread::start... functions and the THREAD_STARTERS namespace.

Quote:
From where did you get a solution like this?

I made it up because I could not start a member function with pthreads or win32, without having boost as a dependancy. If you need any help with it just let me know.
directNoob
directNoob
@dmail:
Ok, I looked over it.
This solution is nice but too heavy for now. For my needs, this is similar
to shoot with cannons on birds, if you know what I mean.
I'm involved into an project and my task a the moment is to present a very very
basic game engine. No sound, no network, nothing except a bare minimum of camera movement and object appearance, including a texture manager and scene manager.
Nothing more. Moreover I have to admit that I even haven´t much experiance with templates. But the book you mentioned in your code descs sound interesting.
Maybe I buy it, it got a good customer rating.

Anyway, thanks again.

Last but not least, a short reflection.
I can't use member functions as thread procs or dialog procs except I'm using wrapper functions for the procs.
With static functions I just can call other static elements. This is bad.
I think, for now I'll be using the ordinary wrapper attempt.

Thanks
Alex

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.