Posted by
| Nick Gammon
Australia (23,046 posts) Bio
Forum Administrator |
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 |
|