home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / lang / cplus / 13501 < prev    next >
Encoding:
Text File  |  1992-09-10  |  6.2 KB  |  170 lines

  1. Xref: sparky comp.lang.c++:13501 comp.windows.open-look:3794 alt.toolkits.xview:855
  2. Path: sparky!uunet!sun-barr!news2me.ebay.sun.com!jethro.Corp.Sun.COM!exodus.Eng.Sun.COM!appserv.Eng.Sun.COM!midniteoil!soloway
  3. From: soloway@midniteoil.Eng.Sun.COM (Mark Soloway)
  4. Newsgroups: comp.lang.c++,comp.windows.open-look,alt.toolkits.xview
  5. Subject: C++ and callback problems (VERY LONG)
  6. Date: 10 Sep 1992 22:28:52 GMT
  7. Organization: Sun Microsystems, Inc.
  8. Lines: 156
  9. Distribution: world
  10. Message-ID: <lavj14INN4ul@appserv.Eng.Sun.COM>
  11. Reply-To: soloway@midniteoil.Eng.Sun.COM
  12. NNTP-Posting-Host: midniteoil
  13.  
  14. From <name kept anonymous to protect the innocent>:
  15.  
  16. > This letter concerns the your article in alt.toolkits.xview.  I have
  17. > tried to implement your method of encapsulating callbacks thru a
  18. > static wrapper function and storing the 'this' pointer as xv_data.
  19. > Two problems have arisen: the first was due to the fact that i ignored
  20. > your short and somewhat cryptic note:
  21. > ->        // If a notify handler has been specified, via
  22. > ->        // "void Button::setNotifyHandler (void (*)(Button *, Event *))",
  23. > ->        // then call it.
  24. > ->            if (object->notifyHandler)
  25. > ->              (*object->notifyHandler)(object, event);
  26. > I called directly object->notifyhandler(), but then calls in derived classes
  27. > were made to the ancestor callback, as the value of
  28. > object->notifyhandler() is known at compile-time.  I then realized what
  29. > u did, and added a private variable which points to the callback, thus
  30. > sort of explicitly writing the late-binding code.  What turns out
  31. > (using g++ 2.1), is that the code is unusable, because the
  32. > private handler receives a hidden this pointer as its first parameter,
  33. > but no such parameter is pushed to the stack in:
  34. > ->        (*object->notifyHandler)(event);
  35. > thus, stepping into a call of the form
  36. >         (*object->notifyhandler(menu, menuitem)
  37. > where menu=x and menuitem=y, and notifyhandler pointing at notifyhandlerproc
  38. > yields
  39. >         notifyhandlerproc(this=x, menu=y, menuitem=junk)
  40. > i could explicitly define the variable notifyhandlerproc to be a
  41. > pointer to a function which receives (obj *, Menu, Menu_item), but how
  42. > portable is this?  and since you stated in your article that this
  43. > method was used in uit, can you please let me know what the portable,
  44. > arm-compliant, overall stable workaround is?
  45.  
  46. After re-reading what I wrote, I can see why my original article may have
  47. been confusing.  I left out a class declaration that would have made example
  48. #1 more clear and I made a mistake in the "notifyProc" part of example
  49. #2 that could make the example very confusing.  In order to correct these
  50. mistakes, I've included portions of the original posting along with commentary
  51. that will hopefully clear up the confusion.
  52.  
  53. -> This article describes a method I use to provide a convenient C++
  54. -> callback interface for XView and provide the ability to encapsulate
  55. -> callback behavior in a subclass.  The method described is used in
  56. -> UIT V2.
  57.  
  58. [text deleted]
  59.  
  60. EXAMPLE 1:
  61.  
  62. -> A basic notifyProc member function that calls a user spcified callback
  63. -> handler might look like this:
  64. -> 
  65. ->     void Button::notifyProc (Panel_item item, Event *event)
  66. ->     {
  67. ->       Button *object = (Button *)xv_get(item,
  68. ->                                         XV_KEY_DATA,
  69. ->                         THIS_POINTER_KEY);
  70. -> 
  71. ->       // If a notify handler has been specified, via
  72. ->       // "void Button::setNotifyHandler (void (*)(Button *, Event *))",
  73. ->       // then call it.
  74. ->           if (object->notifyHandler)
  75. ->             (*object->notifyHandler)(object, event);
  76. ->     }
  77.  
  78. The "notifyHandler" member used here is actually a data member.  The class
  79. might look something like this:
  80.  
  81.     class Button {
  82.     public:
  83.       ...
  84.       void setNotifyHandler (void (*handler)(Button *, Event *))
  85.         {
  86.           notifyHandler = handler;
  87.         }
  88.  
  89.     protected:
  90.       Panel_item xviewButton;
  91.  
  92.     private:
  93.       static void   notifyProc(Panel_item, Event *);
  94.       void        (*notifyHandler)(Button *, Event *);
  95.     }
  96.  
  97. The notifyHandler data member is just a holder for a user specified
  98. callback function.  The user specified callback function should be
  99. a regular external function (not a member function of another or this
  100. class).
  101.  
  102. The function that XView actually calls for the PANEL_NOTIFY_PROC is
  103. "notifyProc".  "notifyProc" does not have an implicit "this" parameter
  104. because it is a static member function.  "notifyProc" needs to be
  105. declared public for use with g++ because it is illegal to use the
  106. address of a private or protected member function (static or non-static)
  107. in g++.  This is not the case for AT&T or ANSI C++.
  108.  
  109. -> This provides a "convenient" callback interface, but it does not provide
  110. -> for encapsulation of callback behavior in the class.  To provide the ability
  111. -> to encapsulate the behavior, you need to provde a virtual function that
  112. -> will be overridden in subclasses that are encapsulating the callback
  113. -> behavior:
  114.  
  115. EXAMPLE 2:
  116.  
  117. ->     class Button {
  118. ->     public:
  119. ->       ...
  120. -> 
  121. ->     protected:
  122. ->       // Make xviewButton protected so that derived classes can get hold
  123. ->       // of the XView button object when inside of their personalized
  124. ->       // handlers.
  125. ->           Panel_item xviewButton;
  126. -> 
  127. ->     private:
  128. ->       static  void notifyProc(Panel_item, Event *);
  129. ->       virtual void notifyHandler(Event *);
  130. ->     }
  131. -> 
  132. ->     void Button::notifyProc (Panel_item item, Event *event)
  133. ->     {
  134. ->       Button *object = (Button *)xv_get(item,
  135. ->                                         XV_KEY_DATA,
  136. ->                         THIS_POINTER_KEY);
  137. -> 
  138. ->       (*object->notifyHandler)(event);
  139. ->     }
  140.  
  141. The "notifyHandler" in this example is an actual member function of the
  142. class.  It should be called as such.  Since I made a mistake in this
  143. example, this is where most of the confusion probably is.  The above
  144. "notifyProc" should be re-written as follows:
  145.  
  146.     void Button::notifyProc (Panel_item item, Event *event)
  147.      {
  148.        Button *object = (Button *)xv_get(item,
  149.                                          XV_KEY_DATA,
  150.                          THIS_POINTER_KEY);
  151.  
  152.        object->notifyHandler(event);
  153.      }
  154.  
  155. -> You can then define the behavior of notifyHandler in a class derived
  156. -> from Button:
  157.  
  158. [text deleted]
  159.  
  160.                      - Mark
  161.  __________________________________________
  162.  \_Mark Soloway (mark.soloway@Eng.Sun.COM)_\
  163.  /_Distributed Systems Services (ToolTalk)_/
  164.  \__SunSoft (A Sun Microsystems Company)___\
  165.  
  166.  
  167.  
  168.