delft@fwi.uva.nl (Andre van Delft) (10/28/90)
The Turbo C++ programmer's manual says: The main use of static members is to keep track of data common to all objects of a class, such as the number of objects created (...) Thus a static member may be used for object creation (and I have a special reason why I do not want a constructor). However its class cannot be abstract, which I regret. I wanted class c { public: virtual void vf(int) = 0; static int n; static c* createOne() {n++; return new c;} // NOT OK: c is abstract } class d:c { public: void vf(int) {} } void main() { d*anObject; anObject = d::createOne(); ... } Am I overlooking something? Or should C++ permit the keyword "this" after the keyword "new", so that the following would be legal: c* c::createOne() {n++; return new this;} // 'this' denotes the class! Ok, I know I should use a constructor in such cases. I have a good reason to want static members in abstract classes that make new instances: I am currently working on a parallel extension to C++; this language, Scriptic-C++, has simulation capabilities that are a bit comparable to Simula. Scriptic offers a new, function-like refinement construct named "script". For a shop simulation, a "customer" class with a generator in Scriptic is: class Customer { int birthtime; public: static int n; int i; Customer(){i=n++;} scripts Enter = {printf("customer %3u enters\n",i)} Leave = {printf("customer %3u leaves\n",i)} Live = {birthtime=SimTime }: Enter; GetServed(i); {qtime+=SimTime-birthtime}: Leave; {delete this} static scripts Poisson(t) = for(;;); {duration=RNDNEGEXP(t)}; {new Customer}->Live }; ... scripts Day = Customer::Poisson(3) + HOURS(8) // "+ HOURS(8)" kills script Poisson at closing time This works fine. Note that I could not have taken a Customer constructor in Day; I need a static member function for generating customers. The problem arises when I want to generate other creatures as well (thieves, mice, ...), WITHOUT reimplementing the static Poisson script for each kind of creature. (In Scriptic-C, without classes, this was possible by passing a Customer script or something else as a parameter to a generic Poisson script: POISSON(3,Customer) ...) In Scriptic-C++ I want to inherit from an abstract class, something like: class Creature { public: static int n; int i; Creature(){i=n++;} virtual scripts Live = 0; static scripts Poisson(t) = for(;;); {duration=RNDNEGEXP(t)}; {new this}->Live }; class Customer: Creature { int birthtime; public: scripts Enter = {printf("customer %3u enters\n",i)} Leave = {printf("customer %3u leaves\n",i)} Live = {birthtime=SimTime }: Enter; GetServed(i); {qtime+=SimTime-birthtime}: Leave; {delete this} }; class Thieve: Creature { ... } ... scripts Day = Customer::Poisson(3) + Thieve ::Poisson(210) + Mouse ::Poisson(120) + HOURS(8) To summarize: I want the phrase "new this" permitted in static member functions. I feel it would no be too hard to implement. Any comments? Andre van Delft DELFT@fwi.uva.nl
news@ux.acs.umn.edu (News) (11/01/90)
In article <1400@carol.fwi.uva.nl> delft@fwi.uva.nl (Andre van Delft) writes: >The Turbo C++ programmer's manual says: > > The main use of static members is to keep track of data common to all > objects of a class, such as the number of objects created (...) > >Thus a static member may be used for object creation (and I have a special >reason why I do not want a constructor). However its class cannot be >abstract, which I regret. I wanted > >class c { > public: > virtual void vf(int) = 0; > static int n; > static c* createOne() {n++; return new c;} // NOT OK: c is abstract >} > >class d:c { > public: > void vf(int) {} >} > >void main() { > d*anObject; > anObject = d::createOne(); > ... >} > >Am I overlooking something? Or should C++ permit the keyword "this" after >the keyword "new", so that the following would be legal: > >c* c::createOne() {n++; return new this;} // 'this' denotes the class! > >Ok, I know I should use a constructor in such cases. I have a good reason to >want static members in abstract classes that make new instances: > My solution to your problem would not be that. I had a similar problem in which I had a number of different kinds of records on disk that I wanted to read in, but they all had a few data items in common, and I wanted to treat each record the same, no matter which type it was. I did something like this: class GMCRec : public Sortable { [data items] public: // All these are inherited from Sortable. virtual int OType() const; virtual int IsEqual() const; virtual int IsLessThan() const; virtual void PrintOn(ostream &) = 0; // New ones for this class. virtual void GetFrom(istream &) = 0; virtual GMCRec *newone() = 0; // Constructors.... GMCRec() : [Data items initialized] {} GMCRec(GMCRec &other) : [Data items initialized] {} virtual ~GMCRec() {} }; istream &operator >>(istream &in, GMCRec &rec) { rec.GetFrom(in); return(in); } class SeafoodRec : public GMCRec { [extra data items] public: // From GMCRec. virtual int OType() const; virtual void PrintOn(ostream &); virtual void GetFrom(istream &); virtual GMCRec *newone(); // ........ }; GMCRec *SeafoodRec::newone() { return new SeafoodRec(); } When I discovered what sort of records I was going to be reading for this run, I made a master record that was a pointer to a record of the proper type, and whenever I needed a new one to store another record in, I made a call to master->newone() and got a record of the proper type. In my opinion, your construct is unneccesary, at least not for the purpose which you state. Have fun, UUCP: rutgers!umn-cs!donald.cs.umn.edu!hopper (Eric Hopper) __ /) /**********************/ / ') // * I went insane to * / / ______ ____ o // __. __ o ____. . _ * preserve my sanity * (__/ / / / <_/ / <_<__//__(_/|_/ (_<_(_) (_/_/_)_ * for later. * /> * -- Ford Prefect * Internet: </ /**********************/ hopper@donald.cs.umn.edu -- -- Nils_McCarthy mtymp01@ux.acs.umn.edu rutgers!umn-cs!ux.acs.umn.edu!mtymp01 "The wonders of modern technology..." :-) :-) :-)