[comp.lang.c++] Again: Pointer to methods ?

dingelde@viktoria.grz (Dennis Dingeldein) (08/10/90)

Hello!

I scanned our old articles of "comp.lang.c++" but couldn`t find a *real*
solution to the following problem. 
I`m sorry if that problem was already solved last year :-)

Problem:

1. The method of my class needs to accept a pointer to a method of another
class.
	MyClass::SetPointer( <Method of another class> )

2. At compile time of my class I don`t know anything about the other class.

3. SetPointer must be a *method* (of my class), no C function.

4. A solution like "Use a third class with virtual method "SetPointer" and
derive from that class "SetPointer" methods with the appreciated parameters"
is not the one I like to use. This seems to me like "programming around the 
problem because I couldn`t solve it".

I`ll give a simple example, what I wan`t to do with that method

// ----- start of example

// class Menu provides a pulldown functionality
class Menu {

public:
	SetPointer( ???? ); // the method ???? will be called if any
			    // Menu Entry is selected (not senseful, I know)
	Start(); // display and start the interaction with the menu
	...
};

// class Circle is unknown class, here only for the example visible
// it provides the output behaviour of a circle.
class Circle {

public:
	Draw(); // displays the circle
};

// main shows a menu and draws the circle on selection
main() {
	Menu MyMenu( "Draw Circle" );
	Circle MyCircle( ... );

	MyMenu.SetPointer( MyCircle::Draw( ... ) );

	// If the User selects an entry , the circle is drawn!
	Menu.Start();
}

Who know's what to do ? What`s the prototype of Method "SetPointer" ?

Dennis Dingeldein	ZGDV Zentrum fuer Graphische Datenverarbeitung
(dingelde@zgdvda.uucp)	Wilhelminenstr. 7
			D-6100 Darmstadt, West Germany
			Phone: +49/6151/155-121

vaughan@mcc.com (Paul Vaughan) (08/12/90)

I tried to mail this directly using reply, but my mail bounced.
Anyway, it might be interesting to many people.

dingelde@viktoria.grz (Dennis Dingeldein) wrote:

	Problem:

	1. The method of my class needs to accept a pointer to a method of another
	class.
		MyClass::SetPointer( <Method of another class> )
	
	2. At compile time of my class I don`t know anything about the other class.

	3. SetPointer must be a *method* (of my class), no C function.

	4. A solution like "Use a third class with virtual method "SetPointer" and
	derive from that class "SetPointer" methods with the appreciated parameters"
	is not the one I like to use. This seems to me like "programming around the 
	problem because I couldn`t solve it".




	// main shows a menu and draws the circle on selection
	main() {
		Menu MyMenu( "Draw Circle" );
		Circle MyCircle( ... );

		MyMenu.SetPointer( MyCircle::Draw( ... ) );

		// If the User selects an entry , the circle is drawn!
		Menu.Start();
	}

	Who know's what to do ? What`s the prototype of Method "SetPointer" ?

Make the function passed to SetPointer be a 

void (*)()

instead of a member function of the other class.  You can declare it
statically in the code for the other class.  If you need to have it
call a member function, you're going to have to arrange for the object
pointer to be passed in and also be stored when you do the SetPointer,
like this:

void MyMenu::SetPointer(void*, void (*)())

and in some other file


static void myfunc(void* self) { ((Foo*) self)->Draw(); }

and call

	MyMenu::SetPointer((Foo*) this, myfunc)

at some point.


Of course, this isn't completely type-safe, but it is fairly simple to
manually verify type safety, given that myfunc is static and you
probably only call SetPointer once in the file, and the MyMenu
probably handles recording the void* and void (*)() together and
doesn't mess with them much.  

Probably the best solution is one you arbitrarily threw out.

Have some kind of menu selection class

class SelectionAction {
public:
  virtual void Select();
};

and derive specialized versions of that and pass them to the menu via
SetPointer (although "SetPointer" seems like a particularly obtuse
name for the function that does this).  For instance for your circle
object, you could either use multiple inheritance, or something like
this:


class MyMenu {
public:
  void SetPointer(SelectionAction*);
private:
  void MakeSelection();
  SelectionAction* selectionAction;
}

void MyMenu::SetPointer(MySelection* s) { selectionAction = s; }
void MyMenu::MakeSelection() { selectionAction->Select(); }


and in the other file

class Circle;

class CircleSelectionAction {
public:
  CircleSelectionAction(Circle*);
  void Select();
protected:
  Circle* circle;
};

CircleSelectionAction::CircleSelectionAction(Circle* c) : circle(c)
{}



class Circle {
public:
  Circle();
  Draw();
private:
  CircleSelectionAction action;
};


void CircleSelectionAction::Select() { circle->Draw(); }

Circle::Circle() : action(this)
//It may be better to make action pointer and initialize it in the
//constructor body.  That way you could take CircleSelectionAction out
//of the .h file above and avoid cluttering your name spaces.  But
//then you have to use a destructor to get rid of it.

and at some point call

MyMenu::SetPointer(&this->action);

If you need additional arguments passed into the Draw function, you
can put them into the action object.  If you decide to pass additional
arguments to the Select method, that's easy enough to do.
-- 
 Paul Vaughan, MCC CAD Program | ARPA: vaughan@mcc.com | Phone: [512] 338-3639
 Box 200195, Austin, TX 78720  | UUCP: ...!cs.utexas.edu!milano!cadillac!vaughan

 Paul Vaughan, MCC CAD Program | ARPA: vaughan@mcc.com | Phone: [512] 338-3639
 Box 200195, Austin, TX 78720  | UUCP: ...!cs.utexas.edu!milano!cadillac!vaughan

gwu@nujoizey.Berkeley.EDU (George Wu) (08/15/90)

In article <2292@zgdvda.zgdvda.uucp>, dingelde@viktoria.grz (Dennis
Dingeldein) writes:
|> // class Menu provides a pulldown functionality
|> class Menu {
|> 
|> public:
|> 	SetPointer( ???? ); // the method ???? will be called if any
|> 			    // Menu Entry is selected (not senseful, I know)
|> 	Start(); // display and start the interaction with the menu
|> 	...
|> };
|> 
|> // class Circle is unknown class, here only for the example visible
|> // it provides the output behaviour of a circle.
|> class Circle {
|> 
|> public:
|> 	Draw(); // displays the circle
|> };
|> 
|> // main shows a menu and draws the circle on selection
|> main() {
|> 	Menu MyMenu( "Draw Circle" );
|> 	Circle MyCircle( ... );
|> 
|> 	MyMenu.SetPointer( MyCircle::Draw( ... ) );
|> 
|> 	// If the User selects an entry , the circle is drawn!
|> 	Menu.Start();
|> }

     We do similar stuff in some of our code.  For us, class Circle and all
similar classes inherit from a base class, say class Callable.  Then the
Menu::SetPointer() argument is just a pointer to a member function of class
Callable.  The parameters passed to the to be invoked later function are
of course fixed.

							George


----
George J Wu                           | gwu@tcs.com or ucbcad!tcs!gwu
Software Engineer                     | 2121 Allston Way, Berkeley, CA, 94704
Teknekron Communications Systems, Inc.| (415) 649-3752