Posted by
| Nick Gammon
Australia (23,046 posts) Bio
Forum Administrator |
Message
| The next example demonstrates various ways of getting information from the data in the list.
To save worrying about pointers and deleting them I have reworked the earlier class to be "straight" (not a list of pointers to people, just a list of people). In order to support this I added a copy and assignment operator.
The various ways of outputting the person's name, email and age are:
- Via a function built into the class (Person::Print)
- Via a separate function (PrintPerson)
- Via a function object (fPrint) which takes an output stream as an argument. Two examples here show outputting directly to cout, or to an output stream (so the output can be a string inside the program).
- Via an ostream iterator (ostream& operator<<) which lets you stream output from the Person object to an output stream.
- Using remove_copy_if to selectively output to the ostream iterator - this lets you print a subset of the list.
- Doing the same thing but to a custom-written iterator - this would let you totally control what was output and where it went.
All of the above may make this example look a bit cluttered, but you only need to use one of the methods in practice, however the example shows there are lots of ways of achieving a similar result.
#include <string>
#include <list>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iterator>
#include <functional>
using namespace std;
class Person
{
// private members
string m_sName;
string m_sEmail;
int m_iAge;
public:
// constructor
Person (const string sName,
const string sEmail,
const int iAge) :
m_sName (sName), m_sEmail (sEmail), m_iAge (iAge) {};
// default constructor
Person () : m_iAge (0) {};
// copy constructor
Person (const Person & p) :
m_sName (p.m_sName), m_sEmail (p.m_sEmail), m_iAge (p.m_iAge) {};
// operator =
Person & operator= (const Person & rhs)
{
// don't assign to self
if (this == &rhs)
return *this;
m_sName = rhs.m_sName;
m_sEmail = rhs.m_sEmail;
m_iAge = rhs.m_iAge;
return *this;
};
// this is a bit wacky but the MS compiler would not compile
// (the for_each) without a return value, however who cares
// what it is?
// print this person
int Print (void)
{
cout << m_sName
<< " - " << m_sEmail
<< ", age " << m_iAge
<< endl;
return 0; // return value gets discarded
};
// access private members
string GetName () const { return m_sName; };
string GetEmail () const { return m_sEmail; };
int GetAge () const { return m_iAge; };
}; // end of class Person
// ostream iterator for Person class
ostream& operator<< (ostream& os, const Person & p)
{
os << p.GetName ()
<< " - " << p.GetEmail ()
<< ", age " << p.GetAge ()
<< endl;
return os;
}; // end of ostream& operator<<
// my own iterator can be used for outputting
class myiterator : public iterator <output_iterator_tag, Person>
{
public:
// assignment is used to output the value
myiterator & operator= (const Person & p)
{
cout << p.GetName () << endl;
return *this;
};
// dereference and increments are no-ops that return
// the iterator itself
myiterator & operator* () { return *this; };
myiterator & operator++ () { return *this; };
myiterator & operator++ (int) { return *this; };
}; // end of class myiterator
// function to print one person
void PrintPerson (const Person & p)
{
cout << p.GetName ()
<< " - " << p.GetEmail ()
<< ", age " << p.GetAge ()
<< endl;
} // end of PrintPerson
// function object to print one person
class fPrint
{
ostream & m_os;
public:
// constructor - remember which stream to use
fPrint (ostream & os) : m_os (os) {};
void operator() (const Person & p)
{
m_os << p.GetName ()
<< " - " << p.GetEmail ()
<< ", age " << p.GetAge ()
<< endl;
};
}; // end of class fPrint
// this function object is used to test a field inside the
// Person class
struct age_less_than : binary_function <Person, int, bool>
{
bool operator() (const Person & p, const int iAge) const
{ return p.GetAge () < iAge; };
}; // end of struct age_less_than
int main (void)
{
// make a list of people
list<Person> people;
// add items to list
people.push_back (Person ("Nick", "nick@some-email-address.com", 15));
people.push_back (Person ("Fred", "fred@nurk.com.au", 100));
people.push_front (Person ("John", "john@smith.com.au", 35));
// print everyone (calls member function Print in the person class)
cout << "Using mem_fun_ref ..." << endl;
for_each (people.begin (), people.end (), mem_fun_ref (&Person::Print));
// print everyone (calls a separate function to print)
cout << "Using PrintPerson ..." << endl;
for_each (people.begin (), people.end (), PrintPerson);
// print everyone (calls a function object to print)
cout << "Using fPrint to cout ..." << endl;
for_each (people.begin (), people.end (), fPrint (cout));
// for copying results into
ostringstream os;
// print everyone to memory
cout << "Using fPrint to memory ..." << endl;
for_each (people.begin (), people.end (), fPrint (os));
cout << "Memory stream contained:" << endl << os.str ();
// print everyone using an ostream_iterator
cout << "Using ostream_iterator ..." << endl;
copy (people.begin (), people.end (), ostream_iterator<Person> (cout));
// remove_copy_if copies everyone EXCEPT those who meet the condition
// (thus removing them, in a sense) so we use not1 to reverse that condition
// use remove_copy_if to show people who meet a condition
cout << "Show people < 20 years old ..." << endl;
remove_copy_if (people.begin(), people.end(),
ostream_iterator<Person>(cout),
not1 (bind2nd (age_less_than (), 20)));
// by using remove_copy_if on its own this time we actually
// get people who are NOT less than 50
// use remove_copy_if to send people who meet a condition to my iterator
cout << "Show people >= 50 years old ..." << endl;
remove_copy_if (people.begin(), people.end(),
myiterator (), // output iterator takes result
bind2nd (age_less_than (), 50));
return 0;
} // end of main
Output
Using mem_fun_ref ...
John - john@smith.com.au, age 35
Nick - nick@some-email-address.com, age 15
Fred - fred@nurk.com.au, age 100
Using PrintPerson ...
John - john@smith.com.au, age 35
Nick - nick@some-email-address.com, age 15
Fred - fred@nurk.com.au, age 100
Using fPrint to cout ...
John - john@smith.com.au, age 35
Nick - nick@some-email-address.com, age 15
Fred - fred@nurk.com.au, age 100
Using fPrint to memory ...
Memory stream contained:
John - john@smith.com.au, age 35
Nick - nick@some-email-address.com, age 15
Fred - fred@nurk.com.au, age 100
Using ostream_iterator ...
John - john@smith.com.au, age 35
Nick - nick@some-email-address.com, age 15
Fred - fred@nurk.com.au, age 100
Show people < 20 years old ...
Nick - nick@some-email-address.com, age 15
Show people >= 50 years old ...
Fred
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|