Pointer to function

Started by
6 comments, last by Zahlman 18 years, 4 months ago
I have a class that has a pointer to a function as one of it's variables. I assign it to another function in the constructor, but I get a "non-lvalue in assignment" error. I know what that means, but what I want to know is this: Why isn't my value a valid pointer that can be given an address? Here is the appropriate code:
class creature
{
  creature(int whichfunc);
  int funca();
  int funcb();
  int (*func)();
}


creature::creature(int whichfunc)
{
  if (whichfunc)
  {
    (*func)() = funca;
  }
  else
  {
    (*func)() = funcb;
  }
}


One more question: how would I call that function? I'm guessing

  *func();
Advertisement
	class Event	{	public:		Event(){}	        virtual void Call(int c)=0;	};	template <class T>        class GuiEvent : public Event	{		void (T::*m_Func)(int);		T* m_This;                int m_Flag;	public:		GuiEvent(T* l_This,void(T::*l_Func)(int),int l_Flag)		{				m_This = l_This;			m_Func = l_Func;			m_Flag = l_Flag;		}		void Call(int l_Flag)		{			if(m_This && m_Func)			{				(*m_This.*m_Func)(l_Flag);			}		}	};


http://www.newty.de/fpt/functor.html
Insufficent Information: we need more infromationhttp://staff.samods.org/aiursrage2k/
Member function pointers and function pointers are two different things.

What you have defined is a pointer to a function, not a pointer to a member function.

class MemFnPtrTest{public:  // constructor  MemFnPtrTest( int nWhich );private:  // typedefs  typedef int (MemFnPtrTest::*FnPtr)( void );  // private member functions  int    MemberFn1( );  int    MemberFn2( );  void   SomeFn( );  // member variables  FnPtr  m_MemberFnPtr;};inline MemFnPtrTest::MemFnPtrTest( bool bFn1 ){  m_MemberFnPtr = bFn1 ? &MemFnPtrTest::MemberFn1 : &MemFnPtrTest::MemberFn2;}


To actually use the member function pointer, you have to have a reference / pointer to an object before you can execute the function.

void MemFnPtrTest::SomeFn( ){  (this->*m_MemberFnPtr)();}


Hope this helps.
Of course, that fixes the right side of the assignment, but the compiler is currently too busy complaining about the left side :) When you write "int (*func)();", that declares a member whose name is "func" and whose type is "int(creature::*)()". When we assign things, we want to write the variable name, not its type (or any part of the notation therefor). Thus "(*func)()" is not what you want on the left side: that means "evaluate func, and the result of that evaluation is what I want to assign to". You can assign to an int-typed variable, but you can't assign to an int returned from a function - it's not an l-value. What you want on the left side is just "func".

That said, chances are good your real code doesn't really need and won't benefit from function pointers being used in this way. If the idea is that the creature behaves in either the funca() or the funcb() way at different times, then the simple way is to just have a data member that encodes which one to use, and code func() to do an if-check (or switch) on that data. As there get to be more cases, you may instead want to look into the Strategy pattern.

I was actually using it to represent the ai for the creature. I hypothesize that it will become faster to use a pointer than a switch when I get about 20 different behaviors. I tdefinitely needs to be profiled both ways though.
class creature{  creature(int whichfunc);  int funca();  int funcb();  int (creature::*func)();}creature::creature(int whichfunc){  if (whichfunc)  {    func = &creature::funca;  }  else  {    func = &creature::funcb;  }}

This should work (note these corrected-bold lines), though someone out there has already provided you (better ?) alternatives. Using functors and/or desired patterns as you wish, when calling these functions, simply put:
int iRet = (creature_pInstance ->* (creature_pInstance -> func)) () ;

or
 int iRet = (creature_Instance.*(creature_Instance.func)) () ;

or
 int iRet = (this ->* func) () ;
(If you're calling in it's member functions).
--> The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones <--
Quote:Original post by NIm
I was actually using it to represent the ai for the creature. I hypothesize that it will become faster to use a pointer than a switch when I get about 20 different behaviors. I tdefinitely needs to be profiled both ways though.


Have you considered using the newfangled object-oriented methodology? Instead of pointers to functions and switch statement, you just use the keyword "virtual" in front of your member functions and the rest works like magic.

Quote:Original post by NIm
I was actually using it to represent the ai for the creature. I hypothesize that it will become faster to use a pointer than a switch when I get about 20 different behaviors. I tdefinitely needs to be profiled both ways though.


That's fine, but polymorphism can be used to accomplish the same thing without extra overhead and with much nicer syntax. In your case, what you'd probably do is create a polymorphic class to represent the func() process - say we have an abstract base class "CreatureBehaviour", which we then derive from. Each Creature holds a pointer to CreatureBehaviour, and delegates to it. If there is only one function that CreatureBehaviour really needs to provide (aside from construction and destruction), in C++ we can use the operator() for that instead of a named member function, in order to clean up the syntax a bit:

class CreatureBehaviour {  // whatever else is necessary  public:  virtual CreatureBehaviour* operator() (Creature& owner) = 0;  // We return a pointer to some CreatureBehaviour object so as to represent  // a change in behaviour that results from the execution - if the behaviour  // should stay the same, we can just "return this;".}class Creature {  CreatureBehaviour * action;  public:  void act() {    action = action(*this);  }}


This is the Strategy pattern, specifically the Run and Return Successor variant which I have personally found most useful in the past. In C++, the main difficulty is in managing the objects - you probably should use smart pointers instead of the raw ones that are illustrated (this is something that is much easier in a GC environment).

This topic is closed to new replies.

Advertisement