Home › Forums › C Programming › Pointers to Member Functions
- This topic has 1 reply, 2 voices, and was last updated 20 years, 1 month ago by will.
- AuthorPosts
- October 29, 2004 at 11:31 am #1869niklaeshParticipant
Hello i come across very good tutorial, i think u must check it.
Introduction
This is a brief discussion of C++ ‘Pointers to Functions’ and ‘Pointers to Member Functions’, followed by an example of building a functor template to associate an instance of a class and a pointer to a member function of that class into a transferable object. This can be used as a predicate by STL algorithms or other generic code.Background
A question was posted on the CodeProject Visual C++ forum that led me to researching pointers to members. Subsequently, I’ve tidied the code snippet I presented in that thread into a more generic form and considered some more typical uses.Pointers to Member Functions
A pointer to a plain old function is declared (for example) thus,1bool (*pfn)( int )pfn is a pointer to a function taking a single integer argument and returning a bool. An example usage is:
1234567891011121314bool f1 ( int i )<br />{<br />return i > 10 ;<br />}<br /><br />int main ()<br />{<br />bool (*pfn)(int) ;<br />pfn = f1 ;<br />if ( (*pfn)( 11 ))<br />std::cout << "pfn ( 11 ) truen" ;<br /><br />return 0 ;<br />}The value of pfn becomes an actual function address as understood by the CPU.
A pointer to a member function is a slightly different animal,
1bool (Foo::*pmfn)(int) ;pmfn is a pointer to a member function of class Foo that takes a single integer argument and returns a bool.
1234567891011121314151617181920212223242526class Foo<br />{<br />private :<br />int t_ ;<br />public :<br />Foo ( int t ) : t_ ( t )<br />{<br />}<br />bool f1 ( int i )<br />{<br />return i > t_ ;<br />}<br />} ;<br /><br />int main ()<br />{<br />bool (Foo::*pmfn)(int) ;<br />pmfn = &Foo::f1 ;<br /><br />Foo foo ( 10 ) ;<br />if ( (foo.*pmfn)( 11 ))<br />std::cout << "pmfn ( 11 ) truen" ;<br /><br />return 0 ;<br />}<br />This is obviously a pointless piece of code but it suffices to show the syntax. pmfn can be set to any member function of Foo that matches the signature of an int argument and bool return. The actual implementation of pointers to members depends on whether the class has virtual functions, in which case the pointer must be a combination of the address of the relevant table of virtual function pointers and an offset into it. For a plain old class, the pointer is probably a conventional function pointer. The details are implementation and architecture dependent.
Functors
A functor is an instance of a class or struct that can be treated syntactically as a function.12345678910111213141516struct PlusFunctor<br />{<br />int operator()( int l, int r )<br />{<br />return l + r ;<br />}<br />} ;<br /><br />int main ()<br />{<br />PlusFunctor f ;<br />std::cout << "f ( 3, 4 ) = " << f ( 3, 4 ) << std::endl ;<br /><br />return 0 ;<br />}<br />Function Adaptors
A function adaptor is a functor that allows functions or functors to be combined, or to have arguments bound. One interesting class of function adaptors provided by the STL allows member functions of classes to be called:123456789101112131415161718192021222324252627282930class SomeObject<br />{<br />private:<br />int value_ ;<br />public :<br />SomeObject () : value_ ( 0 )<br />{<br />}<br />SomeObject ( int value ) : value_ ( value )<br />{<br />}<br />void ShowValue ()<br />{<br />std::cout << value_ << " " ;<br />}<br />} ;<br /><br />int main ()<br />{<br />std::vector<someobject> v ;<br />v.push_back ( SomeObject ( 1 )) ;<br />v.push_back ( SomeObject ( 2 )) ;<br />v.push_back ( SomeObject ( 3 )) ;<br />v.push_back ( SomeObject ( 4 )) ;<br />std::for_each ( v.begin (), v.end (),<br />std::mem_fun_ref ( &SomeObject::ShowValue )) ;<br /><br />return 0 ;<br />}<br /></someobject>This is calling the nominated member function for each object in the collection in a reasonably readable and concise manner. But what if we wanted to call a member function of some other object for each object in a collection? A scenario might be applying a list of updates to a document:
12345678910111213141516171819202122class Update<br />{<br />private :<br />// update data<br />public :<br />Update () {}<br />// access functions<br />} ;<br /><br />class Document<br />{<br />private :<br />// document data<br />public :<br />Document () {} ;<br /><br />void ApplyUpdate ( const Update& update )<br />{<br />}<br />// other document functions<br />} ;<br />There are two obvious approaches to applying the updates, hand-code a loop to enumerate the container:
1234567891011template <typename Container><br />void ApplyUpdatesToDocument1 ( Document& doc, Container& updates )<br />{<br />Container::iterator it = updates.begin () ;<br />while ( it != updates.end ())<br />{<br />doc.ApplyUpdate ( *it ) ;<br />++it ;<br />}<br />}<br /></typename>By making the type of the container a template parameter, we can choose to use a vector, a list, a stack etc. The compiler can deduce the type of the container when you make the call:
1234567891011int main ()<br />{<br />std::vector<update> vu ;<br />vu.resize ( 10 ) ;<br />Document doc ;<br /><br />ApplyUpdatesToDocument1 ( doc, vu ) ;<br /><br />return 0 ;<br />}<br /></update>However, it seems inelegant to have to write our own loop when for_each is just sitting there waiting to help. One way to bring for_each into action is to create a custom functor that keeps a reference to the document:
12345678910111213141516171819struct ApplyUpdateFunctor<br />{<br />Document& doc_ ;<br />ApplyUpdateFunctor ( Document& doc ) : doc_ ( doc )<br />{<br />}<br />void operator () ( const Update& update )<br />{<br />doc_.ApplyUpdate ( update ) ;<br />}<br />} ;<br /><br />template < typename Container><br />void ApplyUpdatesToDocument2 ( Document& doc, Container& updates )<br />{<br />std::for_each ( updates.begin (),<br />updates.end (), ApplyUpdateFunctor ( doc )) ;<br />}<br />This is great except that we have to write a functor for each type of operation, store them somewhere, and remember what they do when we come back to the code in a week, month or year.
The Meat of the Biscuit
With some template magic, it’s possible to write a generic functor used like this:1234567template <typename Container><br />void ApplyUpdatesToDocument3 ( Document& doc, Container& updates )<br />{<br />std::for_each ( updates.begin (), updates.end (),<br />mem_fun_bind1 ( doc, &Document::ApplyUpdate )) ;<br />}<br /></typename>The call looks more complex than ApplyUpdatesToDocument2 but it requires no custom functor to be defined elsewhere, and the action is written directly in the for_each call. We want to call doc.ApplyUpdate() for each update. Later, maintenance should hopefully require less trawling through other files.
Here is the generic functor code used above:
1234567891011121314151617181920212223template <typename C, typename Arg, typename Result><br />struct mem_fun_bind1_t : public std::unary_function<Arg, Result><br />{<br />Result (C::*pmf_ )( Arg ) ;<br />C& rC_ ;<br /><br />explicit mem_fun_bind1_t ( C& rC,<br />Result (C::*pmf)( Arg )) : rC_ ( rC ), pmf_ ( pmf )<br />{<br />}<br />Result operator () ( Arg a )<br />{<br />return (rC_.*pmf_) ( a ) ;<br />}<br />} ;<br /><br />template <typename C, typename Arg,<br></typename>typename Result> mem_fun_bind1_t<C, Arg, Result><br />mem_fun_bind1 ( C& c, Result (C::*fn)( Arg ))<br />{<br />return mem_fun_bind1_t <C, Arg, Result>( c, fn ) ;<br />}<br /></typename>The helper function mem_fun_bind1 generates the functor mem_fun_bind1_t. This allows the compiler to deduce the template parameters and simplifies what has to be written by hand. mem_fun_bind1_t is directly analogous to the ApplyUpdateFunctor shown above with the addition of a pointer to the appropriate member function and conversion to a template to allow reuse with different objects and members.
An equivalent functor for binary functions, with two arguments:
1234567891011121314151617181920212223template <typename C, typename Arg1, typename Arg2, typename Result><br />struct mem_fun_bind2_t : public std::binary_function<Arg1, Arg2, Result><br />{<br />Result (C::*pmf_ )( Arg1, Arg2 ) ;<br />C& rC_ ;<br /><br />explicit mem_fun_bind2_t ( C& rC,<br />Result (C::*pmf)( Arg1, Arg2 )) : rC_ ( rC ), pmf_ ( pmf )<br />{<br />}<br />Result operator () ( Arg1 a1, Arg2 a2 )<br />{<br />return (rC_.*pmf_) ( a1, a2 ) ;<br />}<br />} ;<br /><br />template </typename><typename C, typename Arg1, typename Arg2, typename Result><br />mem_fun_bind2_t<C, Arg1, Arg2, Result><br />mem_fun_bind2 ( C& c, Result (C::*fn)( Arg1, Arg2 ))<br />{<br />return mem_fun_bind2_t <C, Arg1, Arg2, Result>( c, fn ) ;<br />}<br /></typename>This binary version would suit the poster of the original std::sort question. Extensions to more (or fewer) arguments, if you can find a use for them, is left as an exercise for the reader.
Build Notes
All code in this article has been built and tested using Visual C++ Version 7.1. This obviously requires the addition of the appropriate include files for iostream, vector, algorithm and functional.There are no files to download, I leave the choice of name for a header file containing the functors and helper functions up to you.
Afterword
This is the first time I’ve come face to face with member function pointers. Investigating them, writing and testing the code snippets for this article have been educational. I’ll be using mem_fun_bind in my work in the future. I hope this article proves of some interest even to those who find templates and the STL offensive to the eye. - November 3, 2004 at 11:11 am #3119willParticipant
Ahsun that was a nice tutorial.
But it would be very best if you mention the website address from where you get that tuorial so that the users can have a look at it & may benifit from that site also.Any how Good work. Whenever you find any good tutorial please do post them here.
Thanks
Saqib
- AuthorPosts
- The forum ‘C Programming’ is closed to new topics and replies.