Path: utzoo!utgpu!news-server.csri.toronto.edu!bonnie.concordia.ca!thunder.mcrcim.mcgill.edu!snorkelwacker.mit.edu!apple!usc!zaphod.mps.ohio-state.edu!pacific.mps.ohio-state.edu!linac!att!ucbvax!lexvmc.vnet.ibm.com!schweitz From: schweitz@lexvmc.vnet.ibm.com ("Eric Schweitz") Newsgroups: comp.lang.c++ Subject: Re: typesafe downward casting and contravariance Message-ID: <9104091317.AA16916@ucbvax.Berkeley.EDU> Date: 9 Apr 91 13:16:34 GMT Sender: daemon@ucbvax.BERKELEY.EDU Lines: 69 Subject: Re: typesafe downward casting References: <28007BC8.D71@tct.com> <1991Apr2.161809.16952@kodak.kodak.com> <27FA1EC4.511C@tct.com> <1991Apr5.150148.21840@kodak.kodak.com> According to cok@islsun.Kodak.COM (David Cok): >>But another use of inheritance is to add functionality to an existing class by >>deriving from it. Now virtual functions which returned Base* will still >>return Base* in the derived class -- so I cannot help losing the object's >>static type. In this context one must either have contravariance on the >>return type of virtual functions or type-safe down casting ... And chip@tct.com (Chip Salzenberg) writes: >Or (another choice): modify the base class for the added functionality >(add a do-nothing virtual function, etc). That's my choice. Possibly (?), another variation on what Chip saying is to add a ``helper'' class to the hierarchy, such as... class Base { /* Can't touch this! */ }; class Helper : public Base { /* Add virtual function hooks */ }; class Derived1 : public Helper { /* la la */ }; class Derived2 : public Helper { /* da da */ }; This would allow someone to use Helper* (or Helper&?) to access objects of classes derived from Base. I'm not sure I agree with the idea that contravariance on the function's return type would make code easier to code, debug, etc. I think that if contravariance were allowed, it would make certain things harder to read. I seems desirable to be able to take an expression one token at a time to analyze it. Here's what I mean by "harder to read." Let's assume that the function sin() is contravariant... int sin (int); float sin (float); complex sin (complex); // implementation of sin's... float f, g; int i, j; i = sin (j); // OK. uses int sin(int) f = sin (g); // OK. uses float sin(float) i = 1 / sin (g); // Which one here? // (let the compiler decide?) // (What if these are user-defined classes? // How would these be promoted/demoted?) i = f / sin (g); // or here? f = sin (i) / g; // or here? complex c; c = sin (i) * sin (f) / sin (j) + sin (g); // what does this mean? Someone may find this easy to read, but I sure don't. :-) It just seems to ``feel nice'' to know what return-type a function has. Comments? Eric