How do I save funtions to be called later?
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 18

Thread: How do I save funtions to be called later?

  1. #1
    Join Date
    Oct 2011
    Posts
    15

    How do I save funtions to be called later?

    Context: I'm going to write a simple, text based game with a combat system that uses an event queue instead of being traditionally turn-based. I'm writing my own event queue (based on linked-list), and that's going well thus far, but I'm stuck on how I actually implement my Events.

    When the user chooses an action in this game, the action, along with in how many time units the action will resolve, is put into an Event. A pointer to that Event is then inserted into my event queue (as a data member of a node). My event queue is always sorted (node are inserted into the right place, and the next one to resolve is always at the front).

    The problem is, I have no idea how to save the function, along with all of its parameters, into the Event. Let's say the user, through the text menu, chose to cast a Sleep spell on a target Orc. If I were using a combat system that resolved actions immediately, then I'd probably write something like this in the program:
    Code:
    user->CastSleep( orc_ptr );
    But in my game, the event doesn't resolve until later. How do I "save" this function call for later, until the event is supposed to resolve? Thanks in advance!

  2. #2
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,583

    Re: How do I save funtions to be called later?

    Taking the title of this thread literally, the most straightforward answer would probably be using function pointers (see, for instance, http://www.codeguru.com/forum/showthread.php?t=505211, though in your case it perhaps would rather be a pointer-to-member-function). However, good (OO) program design often is not what seems natural on first sight. A less low-level approach would be having an enum (or other integral type) member in your action class that later is used to dispatch execution to the action class member function that performs the actual action.

    However, based on the few facts I know about your scenario, it seems to be the most recommendable and really OOP-style solution to use an inheritance hierarchy with virtual functions. Assume a base class named Action that is base to all your action classes. It would have a virtual member function named PerformAction(), perhaps pure virtual, perhaps not, but the main purpose of this function is to be implemented in the derived concrete action classes. Your queue would hold pointers to Action instances. Further assume you have a CastSpell class that of course is derived from Action and has a constructor that takes an enum parameter specifying the concrete spell to cast.

    Your action to cast a sleep spell could then be enqueued something like this:

    Code:
    q.push_back(new CastSpell(Sleep));
    Remember that CastSpell is derived from Action so it's legal to put a pointer to one of its instances into a container with item type Action *. Then, later, that object (and perhaps any other Action object) could be taken from the queue and executed like this (simplest possible sample scenario):

    Code:
    Action *p = q.pop_front();
    p->PerformAction();
    delete p;
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  3. #3
    Join Date
    Oct 2011
    Posts
    15

    Re: How do I save funtions to be called later?

    So how does the enum parameter work? Within class CastSpell, I override PerformAction() and inside that function is a huge set of if/else statements?

    Like, as a simple example somewhere in PerformAction() there might be a
    Code:
    if ( selected_spell == CastSpell::Sleep )
    {
      spellStrength = caster->magicPower();
      attemptSetTargetStatusToAsleep ( target, spellStrength );
    }
    Does this mean that within the CastSpell class, I'd need to maintain (and update every time I add a new spell) within the if/else statements every single possible spell? Within the Action inheritance hierarchy, there would exist the entirety of the possibility of every single action?

    My Creature objects never actually need to know how to perform any actions?

  4. #4
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,583

    Re: How do I save funtions to be called later?

    Quote Originally Posted by tyl998 View Post
    So how does the enum parameter work? Within class CastSpell, I override PerformAction() and inside that function is a huge set of if/else statements?

    [...]

    Does this mean that within the CastSpell class, I'd need to maintain (and update every time I add a new spell) within the if/else statements every single possible spell?
    I would prefer a switch statement over the multiple if/else construct, but otherwise, more or less, yes. However, if you plan to have many different spells and want to simplify maintainance, the design may be refined to use CastSpell itself as a base cass for individual spell classes like CastSleepSpell. There also are other possible variants like for instance using policy objects to specify the concrete behaviour of a spell.

    The key feature of the design I proposed was to use an Action base class and inheritance to enable you to pass action objects to the queue and retrieve them without the queue (and perhaps lots of other code, in general, the more the better) needing to know the concrete nature of the specific action.

    Within the Action inheritance hierarchy, there would exist the entirety of the possibility of every single action?

    My Creature objects never actually need to know how to perform any actions?
    This is the design goal, at least in theory. And of cource it's often desirable to come as close to the theoretic ideal as possible.
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  5. #5
    Join Date
    Oct 2011
    Posts
    15

    Re: How do I save funtions to be called later?

    Quote Originally Posted by Eri523 View Post
    the design may be refined to use CastSpell itself as a base cass for individual spell classes like CastSleepSpell.
    I see, so each individual effect, whether it be Attack_With_Equipped_Weapon, Quaff_Consumable, Cast_Sleep_Spell, or Flee, etc will be its own class. I think I can do something like that.
    Quote Originally Posted by Eri523 View Post
    There also are other possible variants like for instance using policy objects to specify the concrete behaviour of a spell.
    What are policy objects?

    Quote Originally Posted by Eri523 View Post
    The key feature of the design I proposed was to use an Action base class and inheritance to enable you to pass action objects to the queue and retrieve them without the queue (and perhaps lots of other code, in general, the more the better) needing to know the concrete nature of the specific action.
    The queue is only there to sort the items based on which one ought to resolve next, and then always pop the one at the front. It also updates the time_remaining data member within each Action each time the an action is resolved (aka time has moved forward). Should it not do that?

  6. #6
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Fairfax, VA
    Posts
    10,888

    Re: How do I save funtions to be called later?

    Quote Originally Posted by tyl998 View Post
    The problem is, I have no idea how to save the function, along with all of its parameters, into the Event.
    Store it as a std::function, and bind the parameters using std::bind.

    If your compiler isn't new enough to support these C++11 features, there are very similar constructs in the Boost library.

  7. #7
    Join Date
    Oct 2011
    Posts
    15

    Re: How do I save funtions to be called later?

    Quote Originally Posted by Lindley View Post
    Store it as a std::function, and bind the parameters using std::bind.

    If your compiler isn't new enough to support these C++11 features, there are very similar constructs in the Boost library.
    Can you give me some example of how to use function and bind?

    I'm actually finding the idea of using inheritence and pushing Action* onto the stack queue to be attractive. Thinking of going ahead and attemtping to implement that first and seeing how it goes.

  8. #8
    Join Date
    Aug 2008
    Posts
    902

    Re: How do I save funtions to be called later?

    As far as how to use function and bind:

    Code:
    #include <iostream>
    #include <functional>
    
    void myfunction(int n)
    {
    	std::cout << n << std::endl;
    }
    
    int main()
    {
    	std::function<void()> func = std::bind(myfunction, 42);
    	func();
    }

  9. #9
    Join Date
    Oct 2011
    Posts
    59

    Re: How do I save funtions to be called later?

    I'd recommend Eri523's class based design, it is IMHO, cleaner OO approach. It also allows you to have a local storage space for each instance which may be useful, though I can't think of one at the moment.

  10. #10
    Join Date
    Oct 2011
    Posts
    15

    Re: How do I save funtions to be called later?

    Quote Originally Posted by Chris_F View Post
    As far as how to use function and bind:

    Code:
    #include <iostream>
    #include <functional>
    
    void myfunction(int n)
    {
    	std::cout << n << std::endl;
    }
    
    int main()
    {
    	std::function<void()> func = std::bind(myfunction, 42);
    	func();
    }
    This looks simple and awesome. The first argument is the function to be called (how do I use member functions of an object?), and the rest are arguments for that function to be called yes?

  11. #11
    Join Date
    Aug 2008
    Posts
    902

    Re: How do I save funtions to be called later?

    Code:
    #include <iostream>
    #include <functional>
    
    class myclass
    {
    public:
        void member_function(int n);
    };
    
    int add(int a, int b)
    {
        return a + b;
    }
    
    int main()
    {
        myclass a;
        std::function<void()> func = std::bind(&myclass::member_function, a, 42);
        func();
        std::function<int(int)> addOne = std::bind(add, std::placeholders::_1, 1)
        int val = addOne(42); // returns 43
    }

  12. #12
    Join Date
    Oct 2008
    Posts
    1,103

    Re: How do I save funtions to be called later?

    and if you don't like std::bind, you can use lambdas

    Code:
    // ...
    
    int main()
    {
        myclass a;
        std::function<void()> func = [&]{ a.member_function( 42 ); };
    IMHO, it's more readable ( and cool ! ) and eventually introducing future changes to the code becomes much easier than with bind.

  13. #13
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Fairfax, VA
    Posts
    10,888

    Re: How do I save funtions to be called later?

    The documentation for boost::bind (std::bind is very similar):
    http://www.boost.org/doc/libs/1_47_0...bind/bind.html

    The documentation for boost::function (std::function is very similar):
    http://www.boost.org/doc/libs/1_47_0.../function.html

    I agree that lambdas are more readable than bind, but older compilers do not support them.
    Last edited by Lindley; November 13th, 2011 at 10:11 AM.

  14. #14
    Join Date
    Oct 2011
    Posts
    15

    Re: How do I save funtions to be called later?

    I am using Visual Studio 2010 Express. That should be new enough?

  15. #15
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Fairfax, VA
    Posts
    10,888

    Re: How do I save funtions to be called later?

    Yes, it has lambdas.

    I'm not certain whether the syntax above (just putting & in the capture clause) works on it or not. In either that or gcc 4.5.1, I forget which, all captured variables must be explicitly listed in the capture clause.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Azure Activities Information Page

Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center