home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #26 / NN_1992_26.iso / spool / comp / lang / cplus / 16070 < prev    next >
Encoding:
Text File  |  1992-11-10  |  3.1 KB  |  128 lines

  1. Path: sparky!uunet!news.tek.com!psgrain!charnel!rat!usc!cs.utexas.edu!zaphod.mps.ohio-state.edu!uwm.edu!linac!att!att!allegra!alice!bs
  2. From: bs@alice.att.com (Bjarne Stroustrup)
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: Invoking functions passed as parameters
  5. Message-ID: <24149@alice.att.com>
  6. Date: 11 Nov 92 02:55:39 GMT
  7. Article-I.D.: alice.24149
  8. References: <1992Nov10.192709.682@netcom.com>
  9. Organization: AT&T Bell Laboratories, Murray Hill NJ
  10. Lines: 116
  11.  
  12.  
  13.  
  14. dx@netcom.com (dx @ Netcom - Online Communication Services) writes
  15.  
  16.  > In standard C, function pointers passed as paramters are invoked with
  17.  > the standard C syntax, e.g.,
  18.  > 
  19.  >     foo(void (*pf)(parmeters))
  20.  >     {
  21.  >         pf(paremeters)
  22.  >     }
  23.  > 
  24.  > Now suppose I have a class PFCLASS, and pf points to a member function of
  25.  > this class, and within foo I want to apply the method pointed to by pf to
  26.  > an instance of PFCLASS, pointed to by pInstance.
  27.  > 
  28.  > In standard C syntax, I would make the member function take the pointer to
  29.  > the instance as a parameter, and use the standard way to call the function:
  30.  > 
  31.  >     pf(pInstance);
  32.  > 
  33.  > But I wonder if there is some way to invoke the method pointed to by pf
  34.  > in a more C++ like way, such that pInstance turns up as the 'this' pointer
  35.  > in the method, rather than having to pass it as a parameter.
  36.  > 
  37.  > Any ideas?
  38.  
  39. First of all: Naturally, the C style works. You only need to go further
  40. if there is a real need.
  41.  
  42. Consider:
  43.  
  44.     class X {
  45.         // ...
  46.     public:
  47.         // ...
  48.         virtual int f1(int);
  49.         virtual int f2(int);
  50.     };
  51.  
  52.  
  53. Solution #1:
  54.  
  55.     int g1(X* p, int i)
  56.     {
  57.         return p->f1(i);
  58.     }
  59.  
  60. The C-style function g1() calls f1 for a given object. A pointer to g1()
  61. can be passed. This is inelegant in some contexts, but have the advantage
  62. that g1() might be passed to a C program if declared extern "C".
  63.  
  64. Solution #2:
  65.  
  66.     typedef int (X::* PMF)(int);
  67.  
  68. PMF is a pointer to member of X type. We can use it like this:
  69.     
  70.     int g2(X* p, PMF f, int i)
  71.     {
  72.         return (p->*f)(i);
  73.     }
  74.  
  75. g2() calls the member function pointed to by `f' for the object
  76. pointed to by `p.' For example:
  77.  
  78.     int (X::* f)(int) = &X::f1;
  79.     int (X::* ff)(int) = &X::f2;
  80.     X obj;
  81.  
  82.     void m()
  83.     {
  84.         g2(&obj,f,2);    // obj.f1(2)
  85.         g2(&obj,ff,4);    // obj.f2(4)
  86.     }
  87.  
  88. Pointers to members are described in sec5.5 of the reference manual (pg71
  89. of the ARM , pg502 and 167 of ``The C++ Programming Language (2nd edition)'').
  90.  
  91. This solves the problem as stated, but just for fun let's explore this a bit:
  92.  
  93. Solution #3:
  94.  
  95.     class XFunc {
  96.         PFM f;
  97.         X* p;
  98.     public:
  99.         XFunc(PMF ff, X* pp) { f=ff; p=pp; }
  100.         int operator()(int i) { return (p->*f)(i); }
  101.     };
  102.  
  103. That is, an object of class `XFunc' contains the information needed to
  104. call a member function for an object and can be called:
  105.  
  106.     XFunc xf(&X::f1,&obj);
  107.     XFunc xff(&X::f2,&obj);
  108.  
  109.     xf(2);    // obj.f1(2)
  110.     xff(4);    // obj.f2(4)
  111.  
  112. Note that objects of type `func' can be passed around easily and safely:
  113.  
  114.     int xcall(XFunc& x, int i)
  115.     {
  116.         x(i);    // call whatever member function x holds
  117.             // for whatever object x holds a pointer to
  118.     }
  119.  
  120.     void m1()
  121.     {
  122.         xcall(xf,2);    // obj.f1(2)
  123.         xcall(xff,4);    // obj.f1(4)
  124.     }
  125.  
  126. Such ``functional objects'' can be very useful, but as usual one
  127. should only use a technique if there is a real need.
  128.