djones@megatest.UUCP (Dave Jones) (01/16/88)
Greetings++; I've been thinking about how to automate the process of deriving type- secure classes from generic base-classes. I'm not completely happy with the method of doing it that's described in The Book on page 209. As a matter of convention, I would prefer a different style, as illustrated by the following #define from the class-library I am currently building: // A dervied class of Assoc, named _name_, which implements // associative arrays, mapping null-terminated strings to values of // type _value_. #define NAME_TABLE(_name_,_value_) \ class _name_ : public Assoc \ { \ public: \ _name_ () : (sizeof(_value_)) {} \ _value_& operator[] (char* key) \ { return *((_value_*)Assoc::lookup(key));} \ } // note: no semicolon Building the _name_ automatically from the type-names, as on page 209 of The Book, can result in multiple defines. Or, if the user forgets and uses "char*", say, instead of a typename, he will get a jillion nonsense error messages. So, let the user choose the (obligatory) name. Leave off the semicolon. Then you can use it as a class-definition, or as you would a defined type: NAME_TABLE(String_table, char*); // class definition String_table string_table; // uses the derived class // Used like an already defined type... NAME_TABLE(Name_table, struct name_entry) name_table; By the way... point two: I would prefer to be able to define a macro that expands to an anonymous type, then use the macro like a type-descriptor: NAME_TABLE(struct name_entry) lookup_table; But derived classes MUST have names. For one thing, CC complains of syntax-error when the macro expands to, class /* no name */ : public Assoc { public: (struct name_entry)& operator[] (char* key) { return *((_value_*)Assoc::lookup(key));} } lookup_table; Another problem is that the for a class to have a constructor or destructor, the class MUST have a name, so that you can have something to name the constructor or destructor! Okay, so maybe I don't campaign too hard on this second point.
mitsu@well.UUCP (Mitsuharu Hadeishi) (01/19/88)
We've developed a set of macros for deriving from generic classes
that allows full flexibility (and even a kind of multiple inheritance)
without causing the implementor to have to define a whole bunch of
macros. The implementor simply defines the "body" of the class as a macro,
with possible parameters a type or two and a class name. If the
programmer wishes to avoid having to specify a class name, s/he can use
the simplest macro "Declare()" (similar to the "declare()" macro in
The Book.) Declare(), however, is defined in terms of a series of
ever-more precise macros which allow the programmer increasing flexibility.
The "body" macro is NOT a full class declaration, only the "body" of
the class (the member functions). If the programmer wishes to
create his/her own class derived from the base class (say, "ListElement")
s/he can simply say
class NameNode : public ListElement
{
char name[40];
public:
// ...
Inherit(ListElement,NameNode);
};
This is appropriate for those generic classes that almost always
require the addition of data members to be useful (a linked list without
any data is pretty useless.)
We've spent a long time arguing over the names, and have come up
with a fairly simple, standard convention. Of course, all of this will
be rendered unnecessary when and if parameterized classes are introduced
into C++; however, we find it useful for our current needs.
-Mitsu Hadeishi
Electronic Arts
djones@megatest.UUCP (Dave Jones) (01/21/88)
in article <5028@well.UUCP>, mitsu@well.UUCP (Mitsuharu Hadeishi) says: > > > We've developed a set of macros for deriving from generic classes > that allows full flexibility (and even a kind of multiple inheritance) > without causing the implementor to have to define a whole bunch of > macros. .... > > Good for you! But I couldn't figure out what you did. Could you describe the macros? Or better yet, share them with us? -- djones