class Square : public Shape {
public:
virtual void draw() {
cout << "Square::Draw()" << endl;
}
~Square() {
cout << "Square::~Square()" << endl;
}
};
int main() {
vector
vs.push_back(new Circle);
vs.push_back(new Square);
for_each(vs.begin(), vs.end(),
mem_fun(&Shape::draw));
purge(vs);
} ///:~
The for_each( ) algorithm does just what it sounds like it: it passes each element in a sequence to the function object denoted by its third argument. In this case, we want the function object to wrap one of the member functions of the class itself, and so the function object’s "argument" becomes the pointer to the object that the member function is called for. To produce such a function object, the mem_fun( ) template takes a pointer to a member as its argument. The purge( ) function is just a little something we wrote that calls delete on every element of sequence.
The mem_fun( ) functions are for producing function objects that are called using a pointer to the object that the member function is called for, while mem_fun_ref( ) is used for calling the member function directly for an object. One set of overloads of both mem_fun( ) and mem_fun_ref( ) is for member functions that take zero arguments and one argument, and this is multiplied by two to handle const vs. non-const member functions. However, templates and overloading takes care of sorting all that out; all you need to remember is when to use mem_fun( ) vs. mem_fun_ref( ).
Suppose you have a container of objects (not pointers), and you want to call a member function that takes an argument. The argument you pass should come from a second container of objects. To accomplish this, use the second overloaded form of the transform( ) algorithm:.
//: C06:MemFun2.cpp
// Calling member functions through an object reference
#include
#include
#include
#include
#include
using namespace std;
class Angle {
int degrees;
public:
Angle(int deg) : degrees(deg) {}
int mul(int times) {
return degrees *= times;
}
};
int main() {
vector
for(int i = 0; i < 50; i += 10)
va.push_back(Angle(i));
int x[] = { 1, 2, 3, 4, 5 };
transform(va.begin(), va.end(), x,
ostream_iterator
mem_fun_ref(&Angle::mul));
cout << endl;
// Output: 0 20 60 120 200
} ///:~
Because the container is holding objects, mem_fun_ref( ) must be used with the pointer-to-member function. This version of transform( ) takes the start and end point of the first range (where the objects live); the starting point of the second range, which holds the arguments to the member function; the destination iterator, which in this case is standard output; and the function object to call for each object. This function object is created with mem_fun_ref( ) and the desired pointer to member. Notice that the transform( ) and for_each( ) template functions are incomplete; transform( ) requires that the function it calls return a value, and there is no for_each( ) that passes two arguments to the function it calls. Thus, you cannot call a member function that returns void and takes an argument using transform( ) or for_each( ).
Most any member function works with mem_fun_ref( ). You can also use standard library member functions, if your compiler doesn’t add any default arguments beyond the normal arguments specified in the standard.[84] For example, suppose you’d like to read a file and search for blank lines; your compiler may allow you to use the string::empty( ) member function like this:.
//: C06:FindBlanks.cpp
// Demonstrates mem_fun_ref() with string::empty()
#include
#include
#include
#include
#include
#include
#include
#include "../require.h"
using namespace std;
typedef vector
int main(int argc, char* argv[]) {
char* fname = "FindBlanks.cpp";
if(argc > 1) fname = argv[1];
ifstream in(fname);
assure(in, fname);
vector
string s;
while(getline(in, s))
vs.push_back(s);
vector
LSI lsi = find_if(vs.begin(), vs.end(),
mem_fun_ref(&string::empty));
while(lsi != vs.end()) {
*lsi = "A BLANK LINE";
lsi = find_if(vs.begin(), vs.end(),
mem_fun_ref(&string::empty));
}
for(size_t i = 0; i < cpy.size(); i++)
if(cpy[i].size() == 0)
assert(vs[i] == "A BLANK LINE");
else
assert(vs[i] != "A BLANK LINE");
} ///:~
This example uses find_if( ) to locate the first blank line in the given range using mem_fun_ref( ) with string::empty( ). After the file is opened and read into the vector, the process is repeated to find every blank line in the file. Each time a blank line is found, it is replaced with the characters "A BLANK LINE." All you have to do to accomplish this is dereference the iterator to select the current string.
Writing your own function object adapters