psrc@pegasus.ATT.COM (Paul S. R. Chisholm) (12/15/89)
From article <22137@brunix.UUCP>, by sdm@cs.brown.edu (Scott Meyers): > 2. Add an enumerated type to ARC that enumerates each of the > subtypes, and add a virtual function arc_type() that is redefined in > each subclass to return the appropriate value. Then I can write > code like "if (arc->arc_type() == EXECUTABLE) arc->evaluate()". In article <3164@cbnewsl.ATT.COM>, dog@cbnewsl.ATT.COM (edward.n.schiebel) writes: > I found a need to do this once (or twice :-), but (as you mention later) > it suffers from having to modify the base class when you derive a > new type from it. I have a variation on this theme which does not > suffer from this weakness: > class base { > public: > virtual String type(); > }; Well, it's nice that the "class name" is printable, but it doesn't need to be as flexible as a String. In Smalltalk-80 (TM), there's a subclass of String known as Symbol. Symbols are implemented as Strings, but are kept in a table so they're guaranteed unique. Thus, to compare two Symbols, all you have to do is compare the character pointers (in C++; in Smalltalk-80, the "=" operator is the same as the "==" operator, and you just see if two Symbols are identically the same object, I think). So let's say (I haven't run any of these through the compiler): class base { private: static char *Typename; // initialized to "base" somewhere ... public: // type() -- return a pointer to a constant name virtual const char* type() { return Typename; // that is, base::Typename }; static const char* Stype() { return base::Typename; }; ... }; > class derived : public base { > pubic: > static String Stype() {return type_string;} > String type() {return Stype();} > private: > static String type_string; // initialized to "derived" in .c file > }; class derived : public base { private: static char Typename[]; // initialized to "derived" somewhere ... public: const char* type() { return Typename; // that is, derived::Typename }; static const char* Stype() { return derived::Typename; }; }; > Now the test becomes: > if(base_ptr->type() == derived::Stype()) doSomething() > (assuming class String has operator== defined of course). > This test (a String comparison) is not that much more expensive than > an integer test, since in many cases, the comparison will fail in the > first character (unless your clas hierarchy looks like arc_generic, > arc_this, arc_that, arc_theotherthing). The test base_ptr->type() == derived::Stype is just a comparison of two pointers. Can't put them in case statements, though. And you'd better get them right (re-implement it in every class)! Turbo Pascal 5.5 has an interesting approach: the "type name" is the pointer to the "virtual method table", and every object of a virtual class responds to the message "TypeOf". > Ed Schiebel, AT&T Bell Laboratories, dog@vilya.att.com Paul S. R. Chisholm, AT&T Bell Laboratories att!pegasus!psrc, psrc@pegasus.att.com, AT&T Mail !psrchisholm I'm not speaking for the company, I'm just speaking my mind. Smalltalk-80 is a trademark of Parc Place Systems, or Xerox, or somebody.
jimad@microsoft.UUCP (Jim Adcock) (12/19/89)
One trick [from ObjC - gack!] is to maintain your names as pointers to strings to begin with, but when you access that pointer the first time you [automagically] change it to a handle for an entry in a lookup table. Since the table is a limited range of addresses, it is quick and easy to see if the conversion has already been done, and assuming it has been done, the comparison is just a pointer compare. Since the entry in the table is a string with the same characters, when you go back to a flat representation of your object, you automatically change it back to a string representation again. The cost is a couple extra pointer checks to see if the string is in the table [yet] or not. Alternately maintain a hash of the string and compare that.
rminnich@super.ORG (Ronald G Minnich) (01/03/90)
In article <10@microsoft.UUCP> jimad@microsoft.UUCP (Jim Adcock) writes: >One trick [from ObjC - gack!] is to maintain your names as pointers to >strings to begin with, but when you access that pointer the first time >you [automagically] change it to a handle for an entry in a lookup table. >Since the table is a limited range of addresses, it is quick and easy to >see if the conversion has already been done, Anybody else out there recognize this one? To me, it looks just like the 'bundles' S.C. Johnson used in the first YACC paper. A bundle was a pointer to some 'thing' or another bundle. You determined what it was by checking to see if the pointer was in the range of addresses for the table of bundles or 'something else'. Just wondering if anyone else noticed this, ron