Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!radar!cadillac!dsouza From: dsouza@optima.cad.mcc.com (Desmond Dsouza) Newsgroups: comp.lang.c++ Subject: Re: Co-ordinating the polymorphism in C++ Message-ID: Date: 14 Feb 91 21:19:48 GMT References: <1991Feb11.003849.27340@gpu.utcs.utoronto.ca> <600@taumet.com> Sender: news@cadillac.CAD.MCC.COM Distribution: na Organization: MCC CAD Program, Austin, Texas Lines: 94 In-reply-to: steve@taumet.com's message of 11 Feb 91 17:04:20 GMT In article <600@taumet.com> steve@taumet.com (Stephen Clamage) writes: craig@gpu.utcs.utoronto.ca (Craig Hubley) writes: |Now that C++ has three polymorphism mechanisms | - overloading (compile-time) | - templates (link-time) | - virtual functions (run-time) |Is anyone thinking about how to reconcile them ? As it stands now, I can |use overloading to add extra arguments to functions, etc., but I can't do |it in my derived classes because virtuals can't be overloaded, etc. Overloading need have no relation to polymorphism. Templates and polymorphism are orthogonal concepts. Virtual function may be overloaded. The rules for overloading resolution with class derivation is remarkably similar to the virtual function mechanism (in fact, it resembles 'multi-methods' with dispatch based on the derivation closeness of *all* arguments, instead of just the 'this' pointer), except the work is done at compile-time. Templates are the C++ implementation of what Cardelli called 'parametric polymorphism'. You could say templates and class derivation/virtuals are orthogonal, except that template-instantiated classes could have meaningful class-derivation relationships between them. e.g. read-only-list Vs read-only-list Virtual functions may NOT be overloaded in the manner Craig seems to want. A derived class,D, with a virtual functions D::f whose arguments differ from those of its base class,B, HIDES the base class function, and does not override B::f. Doing otherwise breaks type-safety. See ARM p.211 for an example. craig@gpu.utcs.utoronto.ca (Craig Hubley) writes: >To propose one small change, if virtuals could be overloaded in type- >compatible ways (i.e. redefining acceptable rguments as pointers to base >classes in place of pointers to base classes, returning pointers to derived >classes in place of pointers to base classes, and permitting extended >argument lists where defaults have been provided) this would add no more >work to the compiler than a simple decision to exhaust matching on virtual >functions before trying for an exact match at a different level, and no >overhead at all to user programs that did not use these features. > >In effect it is no more than removing some arbitrary constraints on typing ^^^^^^^^^ >that are inconsistent with the rules in the rest of C++, which is exactly >the kind of change we have been seeing between versions of C++. > 'Arbitrary' ? Thats kinda strong! Sometimes inconvenient, yes. 1 Redefining acceptable arguments to be pointers to derived classes (I'm assuming thats what you meant) instead of to base classes will break strong typing. 2 Returning pointers to derived classes in place of pointers to base classes requires a change to function call/return sequences, particularly if the implementation follows the cfront model of laying out multiply-inherited classes and virtual tables. It can, however, be done without compromising type safety. 3 Extended argument lists in the derived class would definitely change the function call sequence, since optional arguments are currently completely resolved at compile time. Note that you *can* have these three together: a. B::f(B*) b. D::f(B*) c. D::f(D*) But b) overrides a), while c) does not override a). 1 --> really boils down to the "contravariant Vs covariant" controversy. The contravariant rule, which guarantees strong typing, does NOT allow D::f(D*) to override B::f(B*). The covariant rule allows it, but can fail at run-time in some circumstances. I think some of these limitations can be avoided if the compiler is allowed to generate 'customized' code, like the Self compiler does. e.g. 2 versions of D::f() -- one to be called from a B* object, the other from a D* object (or multiple entry points) and emit some run-time type checks and type conversions in the B* version. but thats a pretty major change :-) Desmond D'Souza. -- ------------------------------------------------------------------------------- Desmond D'Souza, MCC CAD Program | ARPA: dsouza@mcc.com | Phone: [512] 338-3324 Box 200195, Austin, TX 78720 | UUCP: {uunet,harvard,gatech,pyramid}!cs.utexas.edu!milano!cadillac!dsouza