1 /********************************************************************************
2 *                                                                               *
3 *                           Multiple Inheritance Test                           *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1998,2006 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * $Id: minheritance.cpp,v 1.15 2006/01/22 17:59:02 fox Exp $                    *
9 ********************************************************************************/
10 #include "fx.h"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 /*
16 
17   Test for proper code generation for the case of multiple inheritance.
18 
19   We have tabulated the following cases:
20 
21     | Message map where handler is found | Class which message handler is member of
22   --+------------------------------------+------------------------------------------
23   1 |     derived class                  |        derived class
24   2 |     one of the base classes        |        one of the base classes
25   3 |     derived class                  |        one of the base classes
26   4 |     one of the base classes        |        derived class
27 
28 
29   Ad 1. The most common scenario, and typically presents no problem, as the
30         "this" pointer and pointer-to-member match up.
31 
32   Ad 2. The "this" pointer needs to be adjusted properly so as to resolve to
33         the correct struct offset in the compound object where one of the bases
34         is located.
35 
36   Ad 3. A handler which is defined in the base class is entered into the
37         message map of the derived class.  This is sometimes done to give an
38         existing member function an additional binding to a different message-id.
39 
40         According to the C++ rules (contravariance rule, pp. 420 3rd ed. C++ book),
41         one can assign a pointer to member of base class to a pointer to
42         member of derived class, and thats what we do.
43 
44   Ad 4. This case is, of course, impossible!! I list it here for completeness
45         sake, and to see if you're paying attention...
46 
47 
48   To test properly, we try several orderings of the two base classes.
49   We print out the "this" address in the ctor and the handler so as to see
50   if the correct offset is being added when the handler is actually being
51   called.
52 
53   Note we're currently assuming only one of the base classes is a FOX class;
54   this limitation could be removed by making more macros:
55 
56     FXIMPLEMENT2
57     FXIMPLEMENT3
58         ...
59     ad nauseam
60 
61   Nausea starts at N=2 for me...
62 
63 */
64 /*******************************************************************************/
65 
66 // Non-FOX object
67 class Base1 {
68 protected:
69   int a;
70 public:
71   Base1();
72   virtual ~Base1();
73   };
74 
75 
76 // FOX object
77 class Base2 : public FXObject {
78   FXDECLARE(Base2)
79 protected:
80   int b;
81 public:
82   enum {
83     ID_BASE2=1,
84     ID_LAST
85     };
86 public:
87   long onCmdBase2(FXObject*,FXSelector,void*);
88 public:
89   Base2();
90   virtual ~Base2();
91   };
92 
93 
94 
95 // Non-FOX object
96 class Base3 {
97 protected:
98   int c;
99 public:
100 public:
101   Base3();
102   virtual ~Base3();
103   };
104 
105 
106 // FOX object with mix-in
107 class TwoBaseOne : public Base1, public Base2 {
108   FXDECLARE(TwoBaseOne)
109 protected:
110   int d;
111 public:
112   enum {
113     ID_TWOBASEONE=Base2::ID_LAST,
114     ID_LAST
115     };
116 public:
117   long onCmdTwoBaseOne(FXObject*,FXSelector,void*);
118 public:
119   TwoBaseOne();
120   virtual ~TwoBaseOne();
121   };
122 
123 
124 
125 // FOX object with mix-in
126 class TwoBaseTwo : public Base2, public Base1 {
127   FXDECLARE(TwoBaseTwo)
128 protected:
129   int e;
130 public:
131   enum {
132     ID_TWOBASETWO=Base2::ID_LAST,
133     ID_LAST
134     };
135 public:
136   long onCmdTwoBaseTwo(FXObject*,FXSelector,void*);
137 public:
138   TwoBaseTwo();
139   virtual ~TwoBaseTwo();
140   };
141 
142 
143 // FOX object with mix-in
144 class ThreeBase : public Base3, public TwoBaseOne {
145   FXDECLARE(ThreeBase)
146 protected:
147   int f;
148 public:
149   enum {
150     ID_THREEBASE=TwoBaseOne::ID_LAST,
151     ID_TWOBASEONE,
152     ID_BASE2,
153     ID_LAST
154     };
155 public:
156   long onCmdThreeBase(FXObject*,FXSelector,void*);
157 public:
158   ThreeBase();
159   virtual ~ThreeBase();
160   };
161 
162 
163 /*******************************************************************************/
164 
Base1()165 Base1::Base1(){
166   FXTRACE((100,"Base1::Base1 at %08p\n",this));
167   a=1;
168   }
169 
170 
~Base1()171 Base1::~Base1(){
172   FXTRACE((100,"Base1::~Base1\n"));
173   }
174 
175 /*******************************************************************************/
176 
177 
178 FXDEFMAP(Base2) Base2Map[]={
179   FXMAPFUNC(SEL_COMMAND,Base2::ID_BASE2,Base2::onCmdBase2),
180   };
181 
FXIMPLEMENT(Base2,FXObject,Base2Map,ARRAYNUMBER (Base2Map))182 FXIMPLEMENT(Base2,FXObject,Base2Map,ARRAYNUMBER(Base2Map))
183 
184 Base2::Base2(){
185   FXTRACE((100,"Base2::Base2 at %08p\n",this));
186   b=2;
187   }
188 
onCmdBase2(FXObject *,FXSelector,void *)189 long Base2::onCmdBase2(FXObject*,FXSelector,void*){
190   FXTRACE((100,"Base2::onCmdBase2 at %08p b=%d\n",this,b));
191   return 1;
192   }
193 
~Base2()194 Base2::~Base2(){
195   FXTRACE((100,"Base2::~Base2\n"));
196   }
197 
198 
199 /*******************************************************************************/
200 
201 
Base3()202 Base3::Base3(){
203   FXTRACE((100,"Base3::Base3 at %08p\n",this));
204   c=3;
205   }
206 
207 
~Base3()208 Base3::~Base3(){
209   FXTRACE((100,"Base3::~Base3\n"));
210   }
211 
212 
213 
214 /*******************************************************************************/
215 
216 
217 FXDEFMAP(TwoBaseOne) TwoBaseOneMap[]={
218   FXMAPFUNC(SEL_COMMAND,TwoBaseOne::ID_TWOBASEONE,TwoBaseOne::onCmdTwoBaseOne),
219   };
220 
FXIMPLEMENT(TwoBaseOne,Base2,TwoBaseOneMap,ARRAYNUMBER (TwoBaseOneMap))221 FXIMPLEMENT(TwoBaseOne,Base2,TwoBaseOneMap,ARRAYNUMBER(TwoBaseOneMap))
222 
223 TwoBaseOne::TwoBaseOne(){
224   FXTRACE((100,"TwoBaseOne::TwoBaseOne at %08p\n",this));
225   d=4;
226   }
227 
onCmdTwoBaseOne(FXObject *,FXSelector,void *)228 long TwoBaseOne::onCmdTwoBaseOne(FXObject*,FXSelector,void*){
229   FXTRACE((100,"TwoBaseOne::onCmdTwoBaseOne at %08p d=%d\n",this,d));
230   return 1;
231   }
232 
~TwoBaseOne()233 TwoBaseOne::~TwoBaseOne(){
234   FXTRACE((100,"TwoBaseOne::~TwoBaseOne\n"));
235   }
236 
237 /*******************************************************************************/
238 
239 
240 FXDEFMAP(TwoBaseTwo) TwoBaseTwoMap[]={
241   FXMAPFUNC(SEL_COMMAND,TwoBaseTwo::ID_TWOBASETWO,TwoBaseTwo::onCmdTwoBaseTwo),
242   };
243 
FXIMPLEMENT(TwoBaseTwo,Base2,TwoBaseTwoMap,ARRAYNUMBER (TwoBaseTwoMap))244 FXIMPLEMENT(TwoBaseTwo,Base2,TwoBaseTwoMap,ARRAYNUMBER(TwoBaseTwoMap))
245 
246 TwoBaseTwo::TwoBaseTwo(){
247   FXTRACE((100,"TwoBaseTwo::TwoBaseTwo at %08p\n",this));
248   e=4;
249   }
250 
onCmdTwoBaseTwo(FXObject *,FXSelector,void *)251 long TwoBaseTwo::onCmdTwoBaseTwo(FXObject*,FXSelector,void*){
252   FXTRACE((100,"TwoBaseTwo::onCmdTwoBaseTwo at %08p e=%d\n",this,e));
253   return 1;
254   }
255 
~TwoBaseTwo()256 TwoBaseTwo::~TwoBaseTwo(){
257   FXTRACE((100,"TwoBaseTwo::~TwoBaseTwo\n"));
258   }
259 
260 
261 /*******************************************************************************/
262 
263 
264 FXDEFMAP(ThreeBase) ThreeBaseMap[]={
265   FXMAPFUNC(SEL_COMMAND,ThreeBase::ID_THREEBASE,ThreeBase::onCmdThreeBase),
266   FXMAPFUNC(SEL_COMMAND,ThreeBase::ID_TWOBASEONE,ThreeBase::onCmdTwoBaseOne),
267   FXMAPFUNC(SEL_COMMAND,ThreeBase::ID_BASE2,ThreeBase::onCmdBase2),
268   };
269 
FXIMPLEMENT(ThreeBase,TwoBaseOne,ThreeBaseMap,ARRAYNUMBER (ThreeBaseMap))270 FXIMPLEMENT(ThreeBase,TwoBaseOne,ThreeBaseMap,ARRAYNUMBER(ThreeBaseMap))
271 
272 ThreeBase::ThreeBase(){
273   FXTRACE((100,"ThreeBase::ThreeBase at %08p\n",this));
274   f=5;
275   }
276 
onCmdThreeBase(FXObject *,FXSelector,void *)277 long ThreeBase::onCmdThreeBase(FXObject*,FXSelector,void*){
278   FXTRACE((100,"ThreeBase::onCmdThreeBase at %08p f=%d\n",this,f));
279   return 1;
280   }
281 
~ThreeBase()282 ThreeBase::~ThreeBase(){
283   FXTRACE((100,"ThreeBase::~ThreeBase\n"));
284   }
285 
286 
287 /*******************************************************************************/
288 
289 
290 // Start the whole thing
main(int,char **)291 int main(int,char**){
292   fxTraceLevel=101;
293 
294   {
295   TwoBaseOne twobase1;
296 
297   // Found in TwoBaseOne
298   FXTRACE((100,"calling TwoBaseOne\n"));
299   twobase1.handle(NULL,FXSEL(SEL_COMMAND,TwoBaseOne::ID_TWOBASEONE),NULL);
300 
301   // Found in Base2
302   FXTRACE((100,"calling Base2\n"));
303   twobase1.handle(NULL,FXSEL(SEL_COMMAND,Base2::ID_BASE2),NULL);
304   }
305 
306   FXTRACE((100,"=============\n"));
307 
308   {
309   TwoBaseTwo twobase2;
310 
311   // Found in TwoBaseTwo
312   FXTRACE((100,"calling TwoBaseTwo\n"));
313   twobase2.handle(NULL,FXSEL(SEL_COMMAND,TwoBaseTwo::ID_TWOBASETWO),NULL);
314 
315   // Found in Base2
316   FXTRACE((100,"calling Base2\n"));
317   twobase2.handle(NULL,FXSEL(SEL_COMMAND,Base2::ID_BASE2),NULL);
318   }
319 
320   FXTRACE((100,"=============\n"));
321 
322   {
323   ThreeBase threebase;
324 
325   // Found in ThreeBase
326   FXTRACE((100,"calling ThreeBase\n"));
327   threebase.handle(NULL,FXSEL(SEL_COMMAND,ThreeBase::ID_THREEBASE),NULL);
328 
329   // Found in TwoBaseOne
330   FXTRACE((100,"calling TwoBaseOne\n"));
331   threebase.handle(NULL,FXSEL(SEL_COMMAND,TwoBaseOne::ID_TWOBASEONE),NULL);
332 
333   // Found in Base2
334   FXTRACE((100,"calling Base2\n"));
335   threebase.handle(NULL,FXSEL(SEL_COMMAND,Base2::ID_BASE2),NULL);
336 
337   // Found in TwoBaseOne
338   FXTRACE((100,"calling TwoBaseOne via ThreeBase\n"));
339   threebase.handle(NULL,FXSEL(SEL_COMMAND,ThreeBase::ID_TWOBASEONE),NULL);
340 
341   // Found in Base2
342   FXTRACE((100,"calling Base2 via ThreeBase\n"));
343   threebase.handle(NULL,FXSEL(SEL_COMMAND,ThreeBase::ID_BASE2),NULL);
344   }
345 
346   return 1;
347   }
348 
349 
350