C++ : Pointers to member functions


PART 17


Q112: What is the type of `ptr-to-member-fn'?  Is it diffn't from `ptr-to-fn'?
A: A member fn of class X has type:  Returntype (X::*)(Argtypes)
   while a plain function has type:  Returntype (*)   (Argtypes)



Q113: How can I ensure `X's objects are only created with new, not on the stack?
A: Make constructors protected and define `friend' or `static' fns that return
a ptr to objects created via `new' (the ctors must be protected rather than
private, otherwise you couldn't derive from the class).  Ex:

	class X {	//only want to allow dynamicly allocated X's
	protected:
	           X();
	           X(int i);
	           X(const X& x);
	  virtual ~X();
	public:
	  static X* create()           { return new X();  }
	  static X* create(int i)      { return new X(i); }
	  static X* create(const X& x) { return new X(x); }
	};

	X* Xptr = X::create(5);



Q114: How do I pass a ptr to member fn to a signal handler,X event callback,etc?
A: Because a member function is meaningless without an object to invoke it on,
you can't do this directly (if `X' were rewritten in C++, it would probably
pass references to *objects* around, not just pointers to fns; naturally the
objects would embody the required function and probably a whole lot more).

As a patch for existing software, use a free function as a wrapper which takes
an object obtained through some other technique (held in a global, perhaps) and
calls the desired member function.  There is one exception: static member
functions do not require an actual object to be invoked, and ptrs-to-static-
member-fns are type compatible with regular ptrs-to-fns (see ARM p.25, 158).

Ex: suppose you want to call X::memfn() on interrupt:

    class X {
    public:
             void memfn();
      static void staticmemfn();	//a static member fn can handle it
      //...
    };

    //wrapper fn remembers the object on which to invoke memfn in a static var:
    static X* object_which_will_handle_signal;
    void X_memfn_wrapper() { object_which_will_handle_signal.memfn(); }

    main()
    {
      /* signal(SIGINT, X::memfn); */   //Can NOT do this
      signal(SIGINT, X_memfn_wrapper);  //Ok
      signal(SIGINT, X::staticmemfn);   //Also Ok
    }



Q115: Why am I having trouble taking the address of a C++ function?
Short ans: Please read previous question first; this is a corollary.

Long ans: In C++, member fns have an implicit parameter which points to the
object (the `this' ptr inside the member fn).  Normal C fns can be thought of
as having a different calling convention from member fns, so the types of their
ptrs (ptr-to-member-fn vs ptr-to-fn) are different and incompatible.  C++
introduces a new type of ptr, called a ptr-to-member, which can only be invoked
by providing an object (see ARM 5.5).  Do NOT attempt to `cast' a ptr-to-mem-fn
into a ptr-to-fn; the result is undefined and probably disastrous; a ptr-to-
member-fn is NOT required to contain the machine addr of the appropriate fn
(see ARM, 8.1.2c, p.158).  As was said in the last example, if you want a
regular C fn ptr, use either a top-level (non-class) fn, or a `static' (class)
member fn.



Q116: How do I declare an array of pointers to member functions?
A: Use the following declaration:

	class Frob {
	public:
	  Rettype f(T1 x, T2 y);
	  Rettype g(T1 x, T2 y);
	  Rettype h(T1 x, T2 y);
	  Rettype i(T1 x, T2 y);
	  //...
	};

	Rettype (Frob::*fn_ptr[3])(T1,T2) = { &Frob::f, &Frob::g, &Frob::h };

You can make the array declaration somewhat clearer with a typedef:
	typedef  Rettype (Frob::*Frob_member_ptr)(T1,T2);
	//...
	Frob_member_ptr fn_ptr[3] = { &Frob::f, &Frob::g, &Frob::h };

To call one of the functions on an object `frob', use:
	Frob frob;
	//...
	(frob.*fn_ptr[i])(x, y);

You can make the call somewhat clearer using a #define:
	#define  apply_member_fn(object,fn)   ((object).*(fn))
	//...
	apply_member_fn(frob,fn_ptr[i])(x, y)