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