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-121vaughan@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!vaughangwu@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