[Home] [Downloads] [Search] [Help/forum]


Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to "verify" your details, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ Programming ➜ STL ➜ Function objects

Function objects

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Wed 12 May 2004 09:34 PM (UTC)
Message
Function objects are like ordinary C++ functions, however they (can) have a "state", so that they can remember things (eg. a cumulative total, what sort order you might require, where to output things, and so on).

A function object is a normal C++ class, however inside it implements the "operator ()" - this operator is called whenever the function is to be called by another function.

An example of this is the "for_each" STL algorithm, which calls a function for every item in a range in a container. If you give a function object as the function to be called the function object can use its operator() for each call.

In the example below the fWeigh function object calculates a cumulative weight.

The constructor initialises the total weight to zero, and the operator () is called each iteration by for_each, and it adds up the weight of the current object. It then recurses to weigh owned objects (objects inside objects).

The call to fWeigh is here:


int iWeight = for_each (objectList.begin (), 
                          objectList.end (), 
                          fWeigh ()).GetTotal ();


What this does is (on the third line above) instantiate an instance of fWeigh (passing no parameters in this case, but if you wanted to pass parameters to the function object this would be the place to do it). This instance is used repeatedly in for_each, and then when for_each finishes it returns a reference to the fWeigh instance.

This reference is then used to call GetTotal to retrieve the total calculated during the for_each loop.

On to the code ... it defines a simple "MUD object" class, where each object has a name, weight, and owns other objects.

The destructor deletes the object and its owned objects, so by simply deleting an object you also get rid of subordinate objects, thus not leaving dangling pointers.

There is an internal function Print that prints the current object, and its owned objects, by recursion.

There is a function object fWeigh, mentioned previously, for calculating an object's weight.

The main function creates a few example objects, puts some inside others, and then uses for_each to print the results, and for_each again to calculate the weight of all objects.


#include <list>
#include <string>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iterator>
#include <functional>

using namespace std;

class MudObject;
// a list of object pointers
typedef list<MudObject*> MudObjectList;
  

class MudObject 
  { 
  public:
  
  // constructor 
  MudObject (const string sName, const int iWeight)
    : m_sName (sName), m_iWeight (iWeight)  
    {};
    
  // destructor - delete owned objects
  ~MudObject ();

  // print myself  
  int Print (void) ;
  
  // helper functions
  
  void AddObject (MudObject * item) { m_lContents.push_back (item); };  
  int GetWeight (void) const { return m_iWeight; };
  const MudObjectList & GetContents (void) const { return m_lContents; }
    
  // member variables
  
  private:
   
  string m_sName;   // name of object
  int    m_iWeight;  // weight of it
  MudObjectList m_lContents;  // objects inside it
  
  };  // end of MudObject

// helper function to delete a list of objects
void DeleteObjectList (MudObjectList & thelist)
  {
  for (MudObjectList::const_iterator i = thelist.begin ();
       i != thelist.end ();
       i++)
       delete *i;
  thelist.clear ();    
  } // end of DeleteObjectList
  
// destructor  
MudObject::~MudObject ()
  {
  cout << ":destructor for " << m_sName << endl;  
  DeleteObjectList (m_lContents);
  };  // end of destructor MudObject::~MudObject

// print an object and its contents
int MudObject::Print (void) 
  {
  cout << "Object name = " << m_sName <<
          ", weight = " << m_iWeight <<
          ", contains " << m_lContents.size () << " item(s)." << endl;
          
  // now show contents 
  if (!m_lContents.empty ())
    {
    cout << "--Contents--" << endl;
    for_each (m_lContents.begin (), 
              m_lContents.end (), 
              mem_fun (&MudObject::Print));
    }
          
  return 0;  
  }; // end of MudObject::Print


// function object to get weight of one object
class fWeigh 
  {

  int m_iWeight;

  public:

  // constructor - zero weight
  fWeigh () : m_iWeight (0) { };

  void operator() (const MudObject * obj)
    {
    // add weight of object
    m_iWeight += obj->GetWeight (); 
    // add weight of its contents
    m_iWeight += for_each (obj->GetContents ().begin (), 
                           obj->GetContents ().end (), 
                           fWeigh ()).GetTotal ();   
    };

  int GetTotal (void) const { return m_iWeight; }
  
  };  // end of class fWeigh

int main (void)
  {
 
  // make a few objects
  MudObject * obj1 = new MudObject ("sword", 30);
  MudObject * obj2 = new MudObject ("bread", 2);
  MudObject * obj3 = new MudObject ("bag", 5);
  MudObject * obj4 = new MudObject ("chest", 20);
  
  // put sword in bag  
  obj3->AddObject (obj1);
  
  // put bread in bag  
  obj3->AddObject (obj2);

  // put bag in chest
  obj4->AddObject (obj3);
  
  // our global list of objects
  MudObjectList objectList;
  
  // put the bag into it
  objectList.push_back (obj4); 
  
  // print objects and all contents
  for_each (objectList.begin (), 
            objectList.end (), 
            mem_fun (&MudObject::Print));
    
  // weigh objects and all contents
  int iWeight = for_each (objectList.begin (), 
                          objectList.end (), 
                          fWeigh ()).GetTotal ();
  
  cout << "Total weight = " << iWeight << endl;
  
  DeleteObjectList (objectList);

  return 0;
  }

Output

Object name = chest, weight = 20, contains 1 item(s).
--Contents--
Object name = bag, weight = 5, contains 2 item(s).
--Contents--
Object name = sword, weight = 30, contains 0 item(s).
Object name = bread, weight = 2, contains 0 item(s).
Total weight = 57
:destructor for chest
:destructor for bag
:destructor for sword
:destructor for bread


- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


9,318 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]