home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!zephyr.ens.tek.com!shaman!pogo!jonh.wv.tek.com!user
- From: jonh@pogo.wv.tek.com (Jon Howell)
- Newsgroups: comp.sys.mac.programmer
- Subject: Re: Think C Debugger & Class dynamic typing... summary
- Message-ID: <jonh-140892100942@jonh.wv.tek.com>
- Date: 14 Aug 92 17:16:38 GMT
- References: <jonh-130892150657@jonh.wv.tek.com>
- Sender: nobody@pogo.wv.tek.com
- Followup-To: comp.sys.mac.programmer
- Organization: Tektronix
- Lines: 280
-
- [summary]
- In article <jonh-130892150657@jonh.wv.tek.com>, jonh@pogo (that's me!)
- asked:
- > When you look
- > at a CObject in the Data window of the debugger, and dereference it to open
- > up a view of the object's structure, it views the object as though it were
- > the type it's declared as in the context. Why can't/doesn't it use the type
- > the object *really* is? For example:
- >
- > {
- > CView *hokey;
- >
- > hokey = new CWindow;
- > hokey ->IWindow(blah blah blah);
- > <> hokey ->Update();
- > }
- [I forgot to cast hokey above to make the method lookups work. I need a
- newsreader with a built-in precompiler. :v]
- I also knew I could examine hokey in the debugger as a CWindow with:
- *(CWindow *) hokey
- However, I really wish the debugger could do that on its own.
- Per Mildner <Per.Mildner@csd.uu.se> points out that
-
- PM>There is a macro you can use in the debugger that tells you the class
- PM>name of an object as a string. I don't remember the name but it starts
- PM>with two (or possibly one) underscore. It's in the documentation
- PM>somewhere.
-
- This would come in handy when you don't know just what hokey is at the
- moment, so you could look it up to do the cast.
-
- > Another question: TC provides member() and class_name() (and another I
- > forget) functions for figuring out the dynamic type of an object. I'd
- > like to be able to see if an object I've been passed is of a certain
- > type. However, I don't want to do a string compare (class_name), and
- > member() seems to only tell me if the object is a member of class X or
- > one of its ancestors. Is there a way I can get an integer which
- > uniquely identifies the class? (It'd be extra cool if it gave some info on
- > the hierarchy, but... :v)
- To which markw@wc.novell.COM (Mark Wittenberg) responded to in the best
- way -- with code! I'll include his message with a minimum of butchering
- here. Thanks to you two and d88-jwa@nada.kth.se for the replies.
-
- ----- snip here -----
- OK, there is a way. Here are class.h and class.c that do that and more.
- GetClassID does what you want, and there are several other very useful
- routines as well. You can just use Think's "__class" call directly if
- that's really all that you want (I indicate "not a class" with an id
- of -1 rather than Think's 0).
-
- Note that MapClassNameToID is code largely ripped from oops.c, and this
- code uses unsupported and undocumented features of v5.0.2 (translation:
- I carefully studied oops.h and dug through memory a lot); I've been using
- it a long and it's been very solid for me, but caveat emptor.
-
- NewObjectByClassId is particularly nice because it's noticeably faster
- than new_by_name.
-
- /markw
-
- ---------------- class.h ----------------------
- /*
- * Class.h
- * - Class ID declarations
- *
- * Copyright 1991 Mark Wittenberg
- */
-
- #pragma once
-
- #include <CObject.h>
-
- #define kNilClass (-1)
-
- typedef Str255 MAName;
- typedef int ObjClassID;
-
- ObjClassID GetClassID(CObject *theObject);
- void GetClassName(CObject *obj, MAName theName);
- void GetClassNameFromID(ObjClassID id, MAName theName);
- ObjClassID GetClassIDFromName(const MAName theName);
- ObjClassID MapClassNameToID(const MAName theName);
- void *NewObjectByClassId(ObjClassID currentID);
-
- ---------------- class.c ----------------------
- /*
- * Class.c
- * - Class ID routines
- *
- * Copyright 1991 Mark Wittenberg
- */
-
- #define OOPS_PRIVATE
- #include "Oops.h" // change case so that <TCL Headers>
- doesn't mess us up
- #define INDIRECT
- #ifdef INDIRECT
- #define __new __new_indirect
- #else
- #define __new __new_direct
- #endif
-
- extern void *__new(...);
-
- #if __option(far_code) || __option(far_data)
- ERROR - We assume 2-byte IDs!
- #endif
-
- #include "Class.h"
-
- /*
- * GetClassID
- * - Return the class id of an object.
- */
- ObjClassID
- GetClassID(CObject *obj)
- {
- ObjClassID id;
-
- id = (ObjClassID) __class(obj);
- return (id == 0) ? kNilClass : id;
- } /* GetClassID */
-
- /*
- * GetClassName
- */
- void
- GetClassName(CObject *obj, MAName theName)
- {
- unsigned char *name;
-
- theName[0] = '\0';
- name = (unsigned char *) class_name(obj);
- if( name )
- BlockMove( name, theName, name[0] + 1 );
- } /* GetClassName */
-
- /*
- * GetClassNameFromID
- */
- void
- GetClassNameFromID(ObjClassID id, MAName theName)
- {
- unsigned char *name;
-
- theName[0] = '\0';
- name = (unsigned char *) __class_name(id);
- if( name )
- BlockMove( name, theName, name[0] + 1 );
- } /* GetClassNameFromID */
-
- /*
- * GetClassIDFromName
- */
- ObjClassID
- GetClassIDFromName(const MAName theName)
- {
- ObjClassID id;
-
- id = MapClassNameToID( theName );
- return (id == 0) ? kNilClass : id;
- } /* GetClassIDFromName */
-
- /*
- * MapClassNameToID
- */
- ObjClassID
- MapClassNameToID(const MAName theName)
- {
- struct { void *min, *max; } range;
- register void *p, *q;
-
- asm {
-
- ;;
- ;
- ; establish search range
- ;
- ;;
-
- #if __option(a4_globals)
- movea.l a4,a0
- _RecoverHandle
- _GetHandleSize
- move.l a4,range.min
- add.l a4,d0
- move.l d0,range.max
- #else
- move.l CurStackBase,range.min
- move.l a5,range.max
- #endif
-
- ;;
- ;
- ; search data area for matching name (this could probably be improved)
- ;
- ;;
-
- movea.l range.min,p
- movea.l theName,q
- move.w (q)+,d1 ; D1.W =
- 1st two bytes of name
- @1 cmp.w (p)+,d1
- beq.s @2
- cmpa.l range.max,p
- blo.s @1
- ;
- moveq #0,d0 ; search
- failed
- return
- ;
- @2 movea.l p,a0
- movea.l q,a1
- bra.s @4
- @3 cmpm.b (a0)+,(a1)+
- bne.s @1 ;
- name not found - keep looking
- @4 tst.b -1(a1)
- bne.s @3
-
- ;;
- ;
- ; verify we've found a class info record
- ;
- ;;
-
- moveq #~1,d0
- and.w -4(p),d0
- lea -4(p,d0.w),a0 ; A0 ==>
- dispatch table
- cmpa.l range.min,a0
- blo.s @1 ;
- out of range - try again
- cmpa.l range.max,a0
- bhs.s @1 ;
- out of range - try again
- ;
- moveq #1,d0
- add.w (a0),d0
- lsl.w #DSHIFT,d0
- lea ClassInfo_(name[2])+2(a0,d0.w),a1
- cmpa.l p,a1
- bne.s @1 ;
- sanity check failed - try again
-
- ;;
- ;
- ; now a0 points to the dispatch table
- ;
- ;;
- move.l a0,d0
- #ifdef BASE_REG
- sub.l BASE_REG,d0
- #endif
- return
- }
- } /* MapClassNameToID */
-
- /*
- * NewObjectByClassId
- */
- void *
- NewObjectByClassId(ObjClassID id)
- {
- void *cptr;
-
- asm {
- move.w id,d0
- ext.l d0
- #ifdef BASE_REG
- add.l BASE_REG,d0
- #endif
- move.l d0,cptr
- }
- return __new( cptr );
- } /* NewObjectByClassId */
- --
-
- -----------------------------------------------------------------------------
- jonh@pogo.wv.tek.com Jon Howell
-