[comp.lang.c++] Invoking Member Functions Via Pointers

wilson@brillig.cs.umd.edu (Anne Wilson) (11/08/90)

(I tried to post this yesterday, and it has not yet appeared.  My
apologies if this appears twice. -aw)

AUGHH!

I am having a devil of a time trying to invoke a pointer to member function
through an object which is a base class object for the derived class to
which the member function belongs.  The whole thing is so compliciated,
I have tried to "paraphrase" an example:

class Base_class {
}

class Derived_class : public class {
	void new_function;
}

typedef void (*v_fn_ptr) (void *);

class Container_class {
	Base_class* *list;	// array of pointers to Base_class elements
	Container_class (int obj_count, ... );
	void apply (v_fn_ptr);	// apply function to each element in list
}

Derived_class D1, D2;

Container_class c (2, &D1, &D2);		// create c

// Idea is to apply new_function to both D1 and D2
c.apply (&Derived_class::new_function);		// compiles, but crashes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I have running code which does something very similar and works correctly,
the only difference being that the apply function is called on Base_class
objects rather than Derived_class objects.  So I suspect the binding between
the Derived_class member function and a list item, which is also of type 
Derived_class, is not happening properly.

I have been trying the trick of letting the function appear like any old function
and passing it the address of the Derived_class object as its first argument,
but to no avail.  I typed in the following example from Straustrup, and (guess 
what ...) it ran fine.

#include <stream.h>

class cl
{
public:
	char* val;
	void print (int x) { cout << val << " " << x << nl;};
	cl (char *v) {val = v;}
};

typedef void (*PROC) (void*, int);

main () {
	cl z1 ("z1");
	cl z2 ("z2");
	PROC pf1 = PROC (&z1.print);
	PROC pf2 = PROC (&z2.print);
	z1.print(1);
	(*pf1) (&z1,2);
	z2.print(3);
	(*pf2) (&z2,4);
}

Can anyone help with this??  I am running g++ V 1.37.1 on a VAX.
I would be **very** grateful for any suggestions!

Anne Wilson

fuchs@it.uka.de (Harald Fuchs) (11/09/90)

wilson@brillig.cs.umd.edu (Anne Wilson) writes:
>(I tried to post this yesterday, and it has not yet appeared.  My
>apologies if this appears twice. -aw)
Not here.
>class Base_class {
>}

>class Derived_class : public class {
>	void new_function;
>}

>typedef void (*v_fn_ptr) (void *);

>class Container_class {
>	Base_class* *list;	// array of pointers to Base_class elements
>	Container_class (int obj_count, ... );
>	void apply (v_fn_ptr);	// apply function to each element in list
>}

>Derived_class D1, D2;

>Container_class c (2, &D1, &D2);		// create c

>// Idea is to apply new_function to both D1 and D2
>c.apply (&Derived_class::new_function);	// compiles, but crashes

>Can anyone help with this??  I am running g++ V 1.37.1 on a VAX.
>I would be **very** grateful for any suggestions!
Use real "pointers to members". If you don't know what that is, get a
newer C++ book (they were added to the language after 1985).
Then it goes something like that:

  #include <iostream.h>
  #include <stdarg.h>

  class Base_class {
  public:
    virtual void dfunc () = 0;
  };

  class Derived_class: public Base_class {
    int d;
  public:
    Derived_class (int x): d (x) {}
    void dfunc () { cout << "Derived_class\t" << d << "\n"; }
  };

  class Container_class {
    int num;
    Base_class** list;
  public:
    Container_class (int, ...);
    void apply (void (Base_class::*) ());
  };

  Container_class::Container_class (register int x, ...):
  num (x), list (new Base_class*[num]) {
    cout << num << " elements:";
    va_list ap; va_start (ap, x);
    register Base_class** p = list;
    while (x--) {
      *p++ = va_arg (ap, Derived_class*);
      cout << " " << p[-1];
    }
    va_end (ap);
    cout << "\n";
  }

  void Container_class::apply (void (Base_class::*funcp) ()) {
    register int n = num;
    register Base_class** p = list;
  //  while (n--) ((*p++)->*funcp) ();   // Too complicated for AT&T cfront 2.1
    while (n--) ((*p)->*funcp) (), p++;
  }

  main () {
    Derived_class D1 (1), D2 (2);
    cout << "D1@" << &D1 << ", D2@" << &D2 << "\n";
    Container_class c (2, &D1, &D2);
    c.apply (&Base_class::dfunc);
  }

Note that you can only apply a member function of the base class to a
Base_class* object, but it can be a virtual member function.
--

Harald Fuchs <fuchs@it.uka.de> <fuchs%it.uka.de@relay.cs.net> ...
<fuchs@telematik.informatik.uni-karlsruhe.dbp.de>   *gulp*

kaiser@ananke.stgt.sub.org (Andreas Kaiser) (11/09/90)

In your msg to All, dated <09 Nov 90 08:33>, it said:

 AW> I am having a devil of a time trying to invoke a pointer to member
 AW> function through an object which is a base class object for the
 AW> derived class to which the member function belongs.  The whole thing
 AW> is so compliciated, I have tried to "paraphrase" an example:

You cannot invoke non-static member functions via normal function 
pointers. Member functions have a hidden first argument ("this"). 
For this reason, the C++ language has a special function pointer 
type, the "pointer to member function".

Example:

 class Base_class {
 };

 typedef void (Base_class::*v_fn_ptr)(void);
// This is a pointer to a member function of
// class "Base_class" or it's descendants.

 class Derived_class : public class {
        void new_function();
 };

 class Container_class {
         Base_class *list;
         Container_class (int obj_count, ... );
         void apply (v_fn_ptr);
 };

 Derived_class D1, D2;

 Container_class c (2, &D1, &D2);

Now, if you want to run "apply":

         c.apply (Derived_class::new_function);

and within "apply", this function is called by:

         (list->*function_ptr)();


                Andreas

--  
:::::::::::::::::::: uucp: kaiser@ananke.stgt.sub.org
:: Andreas Kaiser :: fido: 2:509/5.2512 & 2:507/18.7206
::::::::::::::::::::

jbuck@galileo.berkeley.edu (Joe Buck) (11/10/90)

In article <fuchs.658164606@t5000>, fuchs@it.uka.de (Harald Fuchs) writes:
> [ in answer to a query by Anne Wilson ]
> Use real "pointers to members". If you don't know what that is, get a
> newer C++ book (they were added to the language after 1985).

The best book I have seen for explaining pointers to member functions
is Lippman's "C++ Primer" (I highly recommend this book).  Several
introductory C++ books omit the concept entirely!  Throw away such
books.


--
Joe Buck
jbuck@galileo.berkeley.edu	 {uunet,ucbvax}!galileo.berkeley.edu!jbuck	

mjv@objects.mv.com (Michael J. Vilot) (11/10/90)

Anne Wilson asks for help:
> I am having a devil of a time trying to invoke a pointer to member function
> through an object which is a base class object for the derived class to
> which the member function belongs.

class Base_class { ... };

class Derived_class : public Base_class {
	void new_function();
};

typedef void (*v_fn_ptr) (void *);
!! This is declaring a type named `v_fn_ptr' which points to a _non_ member
!! function.

class Container_class {
	...
	void apply (v_fn_ptr);
!! This declares a function taking a non-member function pointer
};

c.apply (&Derived_class::new_function);		// compiles, but crashes
!! This should fail at compile time: it is placing a pointer of type
!! `void (Derived_class::*)(void)' into a pointer of type `void (*)(void*)'

!! It would make more sense to declare the type of `v_fn_ptr' as:
	typedef void (Base_class::* v_fn_ptr)();

> I have been trying the trick of letting the function appear like any old function
> and passing it the address of the Derived_class object as its first argument,
> but to no avail.  I typed in the following example from Straustrup, and (guess 
> what ...)
>
>		typedef void (*PROC) (void*, int);
>
It's a non-portable approach, at best.  The example you cite, from ``The C++
Programming Language'' Section 5.4.5, has a footnote in the version of the book
I have (second printing, March 1986):
	``Later versions of C++ support a concept of pointer to member; cl::*
	means "pointer to member of cl".  For example,
		typedef void (cl::*PROC)(int)''

Note the difference in type between this declaration, and the one above.

Hope this helps,

--
Mike Vilot,  ObjectWare Inc, Nashua NH
mjv@objects.mv.com  (UUCP:  ...!decvax!zinn!objects!mjv)