Newsgroups: comp.lang.c++ Path: utzoo!censor!geac!alias!news From: Reid Ellis Subject: Re: asking an object for its type Message-ID: <1991Feb28.055525.24273@alias.uucp> Sender: Reid Ellis Reply-To: Reid Ellis Organization: Alias Research, Inc. Toronto ON Canada References: <23984@netcom.COM> <1190@sheol.UUCP> <1991Feb19.000449.22255@gpu.utcs.utoronto.ca> <607@taumet.com> <65451@brunix.UUCP> <11284@pasteur.Berkeley.EDU> <1991Feb21.182349.19132@gpu.utcs.utoronto.ca> Date: Thu, 28 Feb 91 05:55:25 GMT In <1991Feb21.182349.19132@gpu.utcs.utoronto.ca> craig@gpu.utcs.utoronto.ca (Craig Hubley) writes: >Right on. This why a simple typeof() won't do either. It is possible >to build a more consistent way to tell what an object can really do, >(e.g. x.hasmember("diameter")) but this is only marginally better since >you are still requiring code to be rewritten and deal with the names, >which you supposedly already dealt with in the class header. > >As you point out, this form of programming is unreliable unless others >consistently point out your convention. Is has a far worse flaw, however, >which also applies to defining a virtual function normally: it is not >possible for the base class programmer to anticipate everything that will >be done by the derived class programmers. It is ridiculous to say that >the solution is to add a diameter of null value, or a virtual that does >nothing, in the base type "shape". It is CIRCLE's problem, but as C++ >works now CIRCLE can't solve it. So shape ends up dealing with all of its >derived type's problems. And code reusability is a myth. The below solution has the two advantages of (a) being very straightforward to code and understand, and (b) being user-extensible in a hierarchical manner. shape.h: // I know the 'extern's aren't neccessary, but I like them. // extern class Circle; extern class UserDefined; // I like 'struct' too, so sue me // struct Shape { virtual Circle *asCircle() { return NULL; } virtual UserDefined *asUserDefined() { return NULL; } } circle.h: struct Circle : Shape { Circle *asCircle() { return this; } } myUserCode.h: extern class Whatever; struct UserDefined : Shape { UserDefined *asUserDefined() { return this; } virtual Whatever* asWhatever() { return NULL; } } This way, if you get a Shape '*s', you can say: Circle *c; if((c = s->asCircle()) != NULL) { // do circle things.. UserDefined *ud; Whatever *w; if((ud = s->asUserDefined()) != NULL && (w = wd->asWhatever()) != NULL) { // do Whatever things.. Actually, if you want to define these things as *never* being allowed to fail [i.e. they will only be called when the application's state *DEMANDS* that they be the type requested, then rather than returning NULL, you can make the base class ASSERT fail, or perr() or whatever. Then you can write code like: shape->asUserDefined()->asWhatever()->whateverMethod(param); Yes, it's typesafe downcasting.. Reid -- Reid Ellis 176 Brookbanks Drive, Toronto ON, M3A 2T5 Canada rae@utcs.toronto.edu || rae%alias@csri.toronto.edu CDA0610@applelink.apple.com || +1 416 446 1644