Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!rutgers!sri-spam!mordor!lll-tis!ptsfa!ihnp4!alberta!calgary!west From: west@calgary.UUCP (Darrin West) Newsgroups: comp.lang.c++ Subject: Re: Questions about C++ Message-ID: <964@vaxb.calgary.UUCP> Date: Wed, 10-Jun-87 12:46:18 EDT Article-I.D.: vaxb.964 Posted: Wed Jun 10 12:46:18 1987 Date-Received: Sat, 20-Jun-87 05:44:06 EDT References: <452@ivax.doc.ic.ac.uk> <125@otc.OZ> Distribution: comp Organization: U. of Calgary, Calgary, Ab. Lines: 342 In article <125@otc.OZ>, mikem@otc.OZ (Mike Mowbray) writes: > Since the article by dcw@doc.ic.ac.uk (Duncan C White) is likely to make > others unnecessarily wary of C++, I decided to reply here, rather than by > direct e-mail. > > In article <452@ivax.doc.ic.ac.uk>, dcw@doc.ic.ac.uk (Duncan C White) says: > > [stuff - omitted] which was replied to, admirably, and politely. > > > o Associated operators like 'in' and 'qua' [ see below ] aren't available > > These are not really needed. You achieve the same result in other ways. See > below. I don't think you can make this blanket statement. There are a lot of simulationists who would not like to live without it. :-) ? > > > Explanation of 'in' and 'qua' : > > ----------------------------- > > > > 1). The boolean SIMULA function : > > > > i in c > > > > returns true if the instance, i, is an instance of the given class, c, > > or if i is an instance of any subclass of c [ false otherwise ] > > > > For example: > > > > a 'car' instance is in 'car' > > a 'car' instance is ALSO in 'vehicle' > > a 'fourwheeler' instance is in 'fourwheeler', 'car' and 'vehicle' > > Interesting. I've never felt the need to use such a feature. By structuring > the inheritance hierarchies properly, this can be avoided, I think. This is probably the best C++ solution to the problem: use what is available! Otherwise you might end up in a situation like "running a C program on an interpreter written in lisp". Each language has its forte's (how DO you make an egrave [or whatever]), but forcing either one to do what the other is good at may lead to problems. > > > 2). The polymorphic SIMULA function : > > > > i qua c > > > > "qualifies" the instance, i, as a class, c. > > > > For example: given the following: > > > >> ref( vehicle ) v; > >> v = new car; //vehicle v is a car: C++ would already object > > > > The following use, fails to compile : > > > >> print v.wheels; // attempt to print the number of wheels > >> // that the car-instance v has. > > > > whereas this is ok: > > > >> print (v qua car).wheels; > > If we had: > class Car : Vehicle { > public: > int wheels() { return 4; } > int refuel(); > }; > > then the following could be done: > > Vehicle *v = (Vehicle*) new Car; > > ((Car*)v)->refuel(); > > Note that explicit casting is necessary to initialise v, since here Car does > not have Vehicle as a public base class. Similarly, to access Car::fuel, a > further explicit cast is required. Needless to say, such constructions are > an indication of poor structure, and should be avoided as much as possible. > [Reformatted without permission:] > > Note: the semantics of qua are a strange mixture of compile-time and > > run-time events. At compile-time, v must be an instance of a car, or an > > instance of a superclass of car, otherwise a compile time error is > > generated. However, at run-time, v is checked to see that it actually > > is 'in' car, and a fatal run-time error is generated if not. This is the crux of the issue. And can be easily dealt with, if you want to spent valuable run time doing it. I rewrote class simset of simula in C++, and ran across the famous check to see if the next linkage element was a link, or a head (ie have we reached the end of the circular list? The following was the solution I came up with. I can't say that I totally understood the simula code I was copying, but attempted to do a "one to one" conversion as best I could. The point of interest is the "in_link" virtual function. It is redifined to return 1 only in link. This allows a run time check of any linkage object to determine its type (sort of). A different way to do this (and I suspect that this is what simula actually does) would be to have a member variable of linkage (say "int type") be set to a unique value in each different derivation of linkage. So link would set "type" equal to one, and head would set "type" equal to 2 in their constructors. This would be slightly faster than dereferencing the virtual function pointers, but does cost at run time (and development time). My personal preference is to find a different way to do the same thing. Since C++ does not provide this facility automatically (qua), why not use your imagination, and come up with a viable alternative. For example have a head object which points to the head and tail, and don't use a circular list (ie mark the end of the list with NULL in the same way that simula marks the end of the list with a head object). simset.h #ifndef NULL #define NULL 0 #endif class link; class head; class linkage { public: linkage *SUC,*PRED; virtual int in_link() {return(0);} /* a better way to do this might be with a flag variable which is set to true only in a "link"'s constructor */ link* suc(); link* pred(); }; class link : public linkage { public: int in_link() {return(1);} void out(); void follow(linkage *); void precede(linkage *); void into(head *); }; class head : public linkage{ public: link* first(); link* last(); int empty() {return(SUC == this);} int cardinal(); void clear(); head(); /* Constructor, run upon creation of new "head" */ }; simset.h #include "simset.h" link* linkage.suc() { if (SUC->in_link()) return((link*)SUC); else return(NULL); /* pointing back at head */ } link* linkage.pred() { if (PRED->in_link()) return((link*)PRED); else return(NULL); /* pointing back at head */ } void link.out() { if (SUC != NULL){ SUC->PRED = PRED; PRED->SUC = SUC; /* can PRED be NULL? */ SUC = PRED = NULL; } } void link.follow(linkage *X) { out(); /* remove from other sets */ if (X != NULL){ if (X->SUC != NULL) { /* can be combined with an && */ PRED = X; SUC = X->SUC; SUC->PRED = X->SUC = this; } } } void link.precede(linkage *X) { out(); if (X != NULL){ if (X->SUC != NULL){ /* can be combined with an && */ SUC = X; PRED = X->PRED; PRED->SUC = X->PRED = this; } } } void link.into(head *S) { precede(S); } head.head() { /* run upon construction of an object of type head */ SUC = PRED = this; } link* head.first() { return(suc()); } link* head.last() { return(pred()); } int head.cardinal() { int i = 0; linkage *x; x = this->suc(); while (x != NULL){ i++; x = x->suc(); } return(i); } void head.clear() { link *x; x = first(); while(x != NULL) { x->out(); x = first(); } } and a test program. #include #include "simset.h" class person : public link{ public: virtual void print() { printf("person\n");} }; class male : public person{ public: virtual void print() { printf("male\n");} }; class female : public person{ public: virtual void print() { printf("female\n");} }; main() { int i; head *h; person *t; h = new head; for (i = 0; i< 10; i++) { (new male)->into(h); (new female)->into(h); (new person)->into(h); } printf("card: %d\n",h->cardinal()); while (!h->empty()){ t = (person*)h->first(); t->print(); t->out(); } } > > C++ does not use any features that require storing information of what types > a thing is derived from. This is for reasons of efficiency, and to adhere to > the basic philosophy that if something doesn't use a feature, it should not > have to pay for it. > > > Finding the Immediate Superclass: > > -------------------------------- > > [ ... deleted ... ] > > > > Question 3 : Can anyone think of a nicer way to implement in ? > > ---------- We tried : > > I would try to re-structure my design so that it was not necessary. > Such things are very inefficient. > > > > >>typedef int boolean ; > >> > >>class universal_class { > >> static char *name = "universal_class"; Were you honestly considering using strcmp to tell you which class you had found? You might want to make "name" or "Name" a virtual function that is redifined upon further derivation. C++ gives me more programming power combined with efficiecy at run time than any other language I have run across. I am using it to write my thesis project, which is a Time Warp emulator. (ie a study of an optimistic synchronisation mechanism which is very useful for distributing a simulation. See "Virtual Time" - David Jefferson ACM '85?) It (C++) has turned out to be quite handy! -- Darrin West, Master's Unit (read: student). ..![ubc-vision,ihnp4]! Department of Computer Science alberta!calgary!west University of Calgary. Can you say '88 Winter Games? Brain fault (cortex dumped)