[comp.lang.c++] pointer to member functions

gbaciu@watcgl.waterloo.edu (George Baciu [CGL]) (03/26/90)

I would like to know if the following can be considered a dependable feature
or a C++ compliler implementation dependent problem.

Consider calling a member function through a pointer whose type is NOT
pointer-to-class-member-function returning type T but, to a "global"
function returning type T - all arguments being of equal type.

It seems to me that cfront 2.0:
	1. does not complain if the appropriate type casting is done;
	2. at run time, the argument list is screwed up by an implicit
	   insertion of "this" pointer, in front of the list of arguments.

This can cause problems if it is C++ implementation dependent.
However, if ALL C++ compilers are to behave in the same manner, then
it can be used as a feature in the cases where the class name
for the function being  called is not known in advance, but the function
return type and arguments are known.

Here is an example:
----------------------------- cut here ------------------------------

// Test for passing arguments through calling a member function through
// a pointer to function in another class.
// NOTE: pointer "this" is passed implicitly, so it screws up the
// argument list. In order to get around it, the function pointer type
// must have as first argument a void pointer and, when it is invoked,
// "this" must be the first argument to be passed through.
// FEATURE or BUG??
//-----------------------------------------------------------------------
// output follows:
// f = 654 fp = 654
// f = 630 fp = 630
// &d = 2147475332
//  b = 2147475336
// D:i=99
// B:i=999
//  n = 23552
//  b = 23556
// D:i=88
// B:i=888
//-----------------------------------------------------------------------

#include	<stdio.h>
#include	<stream.h>

// NOTE the extra argument "const void* p" which must be defined
// so as to take care of the implicit "this" pointer, when the
// function is called through a pointer to function of type PFC

typedef	void	(*PFC)(const void* p, int i);

class C
{
public:
	PFC fp;

	 C(PFC f) : fp(f) {
		cout << "f = " << (int) f << " fp = " << (int) fp << "\n";
	}
	~C()	{}
};

class B
{
static	C	S;
public:
	 B()					{ }
	~B()					{ }
		// NOTE: when printn(i) is called through S.fp, "this"
		// is passed implicitly. So, printn does not need an
		// argument to account for "this".
		void	printn(int i)	{ printf("B:i=%d\n",i); }
		void	runfp(int i)		{ S.fp(this,i); }
};

class D : public virtual B
{
static	C	S;
public:
	 D()					{ }
	~D()					{ }
		void	printn(int i)	{ printf("D:i=%d\n",i); }
		void	runfp(int i)		{ S.fp(this,i); }
};

// Function pointers of functions in classes B and D, respectively,
// assigned to fp pointer of class C.

C	B::S((PFC) &B::printn);
C	D::S((PFC) &D::printn);

main ()
{
	D	d;
	D*	n = new D;
	B*	b = &d;		// this will point to members of d.

	printf("&d = %d\n", (int) &d);
	printf(" b = %d\n", (int)  b);

	d.runfp(99);
	b->runfp(999);

	b = n;
	printf(" n = %d\n", (int)  n);
	printf(" b = %d\n", (int)  b);

	n->runfp(88);
	b->runfp(888);
}
----------------------------- cut here ------------------------------

    -- George Baciu -------------------------------------------------
    |  GBaciu@watcgl.Waterloo.edu        GBaciu@watcgl.UWaterloo.CA  |
    |                  * Computer Graphics Lab *                     |
    |  University of Waterloo - Waterloo, Ontario, Canada - N2L 3B5  |
    ------------------------------------------------------------------