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