Thread: Is this an ideal use for passing functions as an arguement...

  1. #1
    Registered User
    Join Date
    Jul 2006
    Posts
    162

    Is this an ideal use for passing functions as an arguement...

    I decided to scratch the old particle class I wrote for a new better one, the primary goal this time is I want one method to handle the "movement processing" based on certain values which a formula will manipulate.

    Code:
    void MovementInACircle (double a, double b, double c ) // etc...
    void MovementInASquare (double a, double b, double c ) // etc...
    Let's assume I define the classes method as such:

    Code:
    class ParticleManage
    {
    // ...
    public:
    	void Process((*proc)(double, double, double));
    // ...
    During development I'd like to swap out different "movement patterns" to work on them individually... so I might have...

    Code:
    ObjInst->Process((*MovementInACirle)(1.33, 2.342, 1.23));
    I'd like to achieve this effect exactly, this might not be the ideal method and maybe there's a better way.

    I want all movement algorithms as a separate component to the particle manager.
    Am I on the right track?

    I'd go with virtual methods and then override methods, but that doesn't give me a 'dynamic' approach. I might later have controls to swap out which "movement algorithm" will be used at any given time...

    I'm just not 100% sure of my approach on this, I've never used functions as arguments so before I went in to it I thought i'd get some feedback. :-)

  2. #2
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Not sure, if this is any better, but you might also try with function objects.

    Code:
    #include <iostream>
    
    struct BaseMovement
    {
        virtual ~BaseMovement() {};
        virtual void operator() ()const = 0;
    };
    
    struct CircleMovement: public BaseMovement
    {
        virtual void operator() ()const
        {
            std::cout << "In circle... \n";
        }
    };
    
    struct SquareMovement: public BaseMovement
    {
        virtual void operator() ()const
        {
            std::cout << "In square... \n";
        }
    };
    
    void foo(const BaseMovement& m)
    {
        m();
    }
    
    int main()
    {
        foo(SquareMovement());
        foo(CircleMovement());
    }
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  3. #3
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    I think it is rather important to make your environment an object as well.

    It's infinitely simpler to let the environment throw particles around and trace their flight rather than having particles control their own movement. Partly because that never happens in real life, but maybe more importantly that you don't have to find a way to embed lots of algorithms inside of a particle class that may never be used.

    I mean if your environment is something like a square then
    Code:
    square s;
    particle elems[MANY];
    coord here = { 2, 4 };
    rate r = 2;
    
    s.init( elems, MANY );
    // Maybe put all these particles in the middle to start.
    
    s.tosstoward( elems[1], here, r );
    
    particle p;
    s.inject( p, here, r );
    // Let square figure out what  happens to all the other particles
    // when a new particle comes inside at some rate of speed.
    If I'm completely crazy let me know but that seems like a simpler model. Just figure out how you're going to allow particles to move in some environment. Then graph them if you want some output.

  4. #4
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Function pointers are definitely the way to do dynamic function calls in C, but I seriously wonder if you'd not be better off doing this in a more OO way with C++. I know you said you considered it, but I still think you could manage it better than just throwing functions into the equation.

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by simpleid View Post
    I decided to scratch the old particle class I wrote for a new better one, the primary goal this time is I want one method to handle the "movement processing" based on certain values which a formula will manipulate.
    A better method is to derive various movement functions from a common movement base class, e.g.:

    Code:
    class MovementMethod
    {
    public:
        virtual ~MovementMethod();
    
        virtual void move(double a, double b, double c);
    };
    
    class CircleMovement : public MovementMethod
    {
    public:
        // Circle-specific movement
        void move(double a, double b, double c);
    };
    
    class SquareMovement : public MovementMethod
    {
    public:
        // Square-specific movement
        void move(double a, double b, double c);
    };
    
    // etc...
    You can still swap out the "movement algorithm" by associating a specific MovementMethod pointer with each object. You can change this pointer to point to a new movement algorithm at will.

  6. #6
    Registered User
    Join Date
    Jul 2006
    Posts
    162
    huh.... well damn, i never considered making the environment an object before, thanks for that insight citizen, i can't believe i never considered it that way before, i think i'm definitely going to do that, and it will solve a lot of problems i had in a previous attempt... damn... that really is a good idea, lol...

    yea, i think i'm going to do the movements via a base class, this is good. I like it... i was hoping to avoid function pointers just because they don't look very good in code hah...

    :-) thanks, this has helped.

  7. #7
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> ObjInst->Process((*MovementInACirle)(1.33, 2.342, 1.23));

    this is just invoking the callback function directly. the Process function should take the address of callback function, and the three doubles as arguments (unless they're generated internally, of course). if 'Process' is non-virtual, you can simply template it so that it can take both functions and objects as arguments.

    Code:
    class ParticleManage
    {
     public:
     
     template <typename Function>
     void
     Process(Function callback, double a, double b, double c)
     {
                // do stuff
                callback(a, b, c);
     }
    };
     
    void
    MovementInACircle(double a, double b, double c)
    {
            cout << "MovementInACircle(" << a << "," << b << "," << c << ")" << endl;
    }
     
    struct MovementInASquare
    {
        void
        operator () (double a, double b, double c) const
        {
                cout << "MovementInASquare(" << a << "," << b << "," << c << ")" << endl;
        }
    };
     
    int
    main()
    {
        ParticleManage pm;
        pm.Process(MovementInACircle, 0.0, 1.0, 2.0);
        pm.Process(MovementInASquare(), 3.0, 4.0, 5.0);
    }
    if you plan to 'store' the callback you might either stick with functions or else use some sort of functor object (boost::function would do, I believe).
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  8. #8
    Registered User
    Join Date
    Jul 2006
    Posts
    162
    What I may end up doing is designing the application to support 'plug-ins' (via assemblies) so I can build my software as a framework with most algorithms as a separate component. I prefer your approach sebatian, it seems very logical and correct.

    Is there a way to achieve that effect though where all constants and variables are options within the "environment" separate from the functions which control the movement? Can these functions be designed to know ahead of time what variables will exist once called for an execute correctly? More importantly, what is the preferred method for achieving this effect?

    Maybe none of my functions will require input, and I'll make all calculations based on "environment" settings. The application will be the host for the environment, and the algorithms for movement will be stored in assemblies.

    I'm extremely fond of this idea, any information regarding this approach would be greatly appreciated. I'm going to spend some time searching around the net, but I'll keep an eye here for replies.
    Last edited by simpleid; 08-16-2007 at 12:19 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Functions and Classes - What did I do wrong?
    By redmage in forum C++ Programming
    Replies: 5
    Last Post: 04-11-2005, 11:50 AM
  2. calling functions within functions
    By edd1986 in forum C Programming
    Replies: 3
    Last Post: 03-29-2005, 03:35 AM
  3. Factory Functions HOWTO
    By GuardianDevil in forum Windows Programming
    Replies: 1
    Last Post: 05-01-2004, 01:41 PM
  4. Shell functions on Win XP
    By geek@02 in forum Windows Programming
    Replies: 6
    Last Post: 04-19-2004, 05:39 AM
  5. Passing data/pointers between functions #2
    By TankCDR in forum C Programming
    Replies: 1
    Last Post: 11-02-2001, 09:49 PM