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 Artsdjones@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