Function pointers

Started by
11 comments, last by snk_kid 18 years, 9 months ago
Greetings, I'm throwing together a simple GUI for my program, and one of the things I'm trying to do is link items between the GUI and the rest of my program. Check boxes are linked to bools, enums are linked to radio buttons, etc. However, I'm trying to link a button to a function. What do I need to grab the function pointer and assign it to a member variable, so when the button is pressed I can call the function pointed to by the member variable? Thanks.
Advertisement
Assuming C++, I would skip the function pointer and go with a more robust functor approach like boost::function.
To satisfy my curiosity, how would I do it if I didn't use boost?

And yes, this is in C++.
Depends on whether your pointer points to a free function or to a non-static member function.

And no, you can't have both. That's why there are things like boost::function.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Hmm, not sure what you mean. The function I'm trying to point to is a member function of the class that the function pointer is also in.
if you have a function declared: int doSomething(double x, double y)
the applicable data type you could assign this to would look like:

int (*fn)(double,double)

thus if I am interpreting your question correctly, in your button class you might have a mutator function looking something like

public:
void setAction(void (*newFunc)(void)) { actionFunc = newFunc; }
private:
void (*actionFunc)(void);

should you desire to associate arbitrary void functions with the pressing of the button. As far as more general function pointers, as in no specific predefined parameter types, I have never seen them, and logically it doesn't make sense that they would exist for this type of application (otherwise how would you handle passing parameters...)
I'm getting this error:
cannot convert from 'void (__thiscall MyClass::*)(void)' to 'void (__cdecl *)(void)

Here's my setup:
// MyClass.htypedef void (*FunctionPtr) (void);class MyClass {public:   void MyFunction(void);private:   FunctionPtr MyFunctionPtr;};// MyClass.cppMyClass::MyClass(void){   MyFunctionPtr = MyFunction;}void MyClass::MyFunction(void){ // do stuff };

I've tried using '&', MyFunctionPtr = &MyFunction, but the compiler does like that. Putting MyClass:: in front of MyFunction on the assignment doesn't seem to do anything, either. What do I need to do differently?
The short answer is
typedef void (*FunctionPtr) (void);
should be
typedef void (MyClass::*FunctionPtr) (void);


For a longer answer, see my reply to this question.
EDIT: beaten

If you're looking for a quick-and-dirty solution, you could define a subclass ICallback in your button class. This subclass would contain a pure virtual OnClick(CButton &) function. Your button would then have an ICallback * member, which would be initialized to a class deriving from CButton::ICallback, which would in turn implement the OnClick() function. It's fairly simple compared to designing your own functor library, but the whole architecture is fairly ugly IMO.

Example:

class CButton{public:	class ICallback	{	public:		virtual void OnClick(CButton &) = 0;	};	void Click()	{		if (mCallback)			mCallback->OnClick(*this);	}	ICallback * mCallback;};class CMyApp : public CButton::ICallback{public:	void Init()	{		mButton.mCallback = this;	}	void Test()	{		mButton.Click();	}	void OnClick(CButton & button)	{		printf("Clicked!\n");	}private:	CButton mButton;};


This is my own (far-from-perfect, but meets my needs) "functor" library:

template<typename TReturn, typename TArgs>class CFunctor;template<typename TReturn, typename TArgs>class IFunction;template<typename TReturn, typename TArgs>class CGlobalFunction;template<class TParent, typename TReturn, typename TArgs>class CMemberFunction;template<typename TReturn, typename TArgs>class IFunction{public:	virtual void Delete() = 0;	virtual TReturn Call(TArgs args) = 0;};template<typename TReturn, typename TArgs>class CGlobalFunction : public IFunction<TReturn,TArgs>{public:	void Delete() { delete this; }	typedef TReturn (* FuncSig)(TArgs);	CGlobalFunction(FuncSig func)	{		mFunction = func;	}	~CGlobalFunction()	{	}	TReturn Call(TArgs args)	{		return mFunction(args);	}private:	FuncSig mFunction;};template<class TParent, typename TReturn, typename TArgs>class CMemberFunction : public IFunction<TReturn,TArgs>{public:	void Delete() { delete this; }	typedef TReturn (TParent::* FuncSig)(TArgs);	CMemberFunction(TParent * parent, FuncSig func)	{		mParent = parent;		mFunction = func;	}	~CMemberFunction()	{	}	TReturn Call(TArgs args)	{		return (mParent->*mFunction)(args);	}private:	TParent * mParent;	FuncSig mFunction;};template<typename TReturn, typename TArgs>class CFunctor{public:	CFunctor()	{		mFunction = null;	}	~CFunctor()	{		Unbind();	}	void Unbind()	{		if (mFunction)		{			mFunction->Delete();			mFunction = null;		}	}	void Bind(TReturn (* func)(TArgs))	{		Unbind();		if (func)			mFunction = new CGlobalFunction<TReturn,TArgs>(func);	}	template<class TParent>	void Bind(TParent * parent, TReturn (TParent::* func)(TArgs))	{		Unbind();		if (parent && func)			mFunction = new CMemberFunction<TParent,TReturn,TArgs>(parent,func);	}	operator bool()	{		return (mFunction != null);	}	TReturn operator()(TArgs args)	{		return mFunction->Call(args);	}private:	IFunction<TReturn,TArgs> * mFunction;};// Specializationstemplate<typename TReturn>class IFunction<TReturn,void>{public:	virtual void Delete() = 0;	virtual TReturn Call() = 0;};template<typename TReturn>class CGlobalFunction<TReturn,void> : public IFunction<TReturn,void>{public:	void Delete() { delete this; }	typedef TReturn (* FuncSig)();	CGlobalFunction(FuncSig func)	{		mFunction = func;	}	~CGlobalFunction()	{	}	TReturn Call()	{		return mFunction();	}private:	FuncSig mFunction;};template<class TParent, typename TReturn>class CMemberFunction<TParent,TReturn,void> : public IFunction<TReturn,void>{public:	void Delete() { delete this; }	typedef TReturn (TParent::* FuncSig)();	CMemberFunction(TParent * parent, FuncSig func)	{		mParent = parent;		mFunction = func;	}	~CMemberFunction()	{	}	TReturn Call()	{		return (mParent->*mFunction)();	}private:	TParent * mParent;	FuncSig mFunction;};template<typename TReturn>class CFunctor<TReturn,void>{public:	CFunctor()	{		mFunction = null;	}	~CFunctor()	{		Detach();	}	void Unbind()	{		if (mFunction)		{			mFunction->Delete();			mFunction = null;		}	}	void Bind(TReturn (* func)())	{		Unbind();		if (func)			mFunction = new CGlobalFunction<TReturn,void>(func);	}	template<class TParent>	void Bind(TParent * parent, TReturn (TParent::* func)())	{		Unbind();		if (parent && func)			mFunction = new CMemberFunction<TParent,TReturn,void>(parent,func);	}	operator bool()	{		return (mFunction != null);	}	TReturn operator()()	{		return mFunction->Call();	}private:	IFunction<TReturn,void> * mFunction;};


Example:

class CButton{public:	void Click()	{		if (OnClick)			OnClick(*this);	}	CFunctor<void,CButton &> OnClick;};class CMyApp{public:	void Init()	{		mButton.OnClick.Bind(this,MyClickHandler);	}	void Test()	{		mButton.Click();	}	void MyClickHandler(CButton & button)	{		printf("Clicked!\n");	}private:	CButton mButton;};
Hmm, ok, I appear to be able to pass around the function pointer now, but how do I call it? If I just state the variable that the function pointer is assigned to, it skips over it. If I put '()' after it, I get the compile error, 'term does not evaluate to a function'.

Also, what if I try to pass the function pointer between different classes? Is that even possible?

This topic is closed to new replies.

Advertisement