craig@gpu.utcs.utoronto.ca (Craig Hubley) (02/10/91)
I was wondering if anyone on the ANSI committee had given any thought to reconciling the way virtual functions and overloading deal with polymorphism. While virtual functions are supposed to provide the main means of substituting objects of compatible types, in fact you can do more with overloading than with virtuals, and so far I see no reason for this inconsistency. The rest of this is good fodder for language lawyers. Virtual functions must match return type and order, number, and types of parameters. However, while overloaded functions must match the return type, they permit considerable flexibility in order and types of arguments. Meanwhile, C++ guarantees that a pointer to a derived object is an acceptable (but not exact?) substitute for a pointer to a base object, where required. And overloading of virtual functions is not permitted at all, presumably to avoid confusing interaction of the two separate resolution mechanisms. All of these inconsistencies might add up to a sign that all of these mechanisms might be better resolved into a single unambigous set of rules in ANSI C++. This would involve relaxing some of the arbitrary constraints that exist now. Consider the following, most of which are presently illegal, but are in fact equivalents of very common constructs in other OOPLs. class B { virtual B* foo(D*) {}; // I *said* they were going to be illegal, // didn't I ? Only on a one-pass compiler. :) } class D : public B { // D* is always demotable to B*, so the function call B* foo(B*) {}; // D::foo(D*) should be equivalent to D::foo((B*)D*) // It could also be interpreted as B::foo(D*), which // might be why it's illegal, but a simple rule to // exhaust argument matching on virtuals before trying // the base functions (if they are tried at all) would // resolve this ambiguity. } class E : public B { D* foo(B*) {}; // Similarly, any context that ends up calling // D::foo() where B::foo() is expected will // receive a D* value that can be used as a B*. // But C++ says that overloads and virtuals // can't change the return type at all. Why not // allow it where the objects are the same size // and C++ already has a built-in promotion ? } // if all of the above were allowed, extending C++ consistently with the // rules mentioned above yields the following results: // main { B* b; D* d; E* e; b->foo(b); // illegal, fine, B* shouldn't automatically promote b->foo(d); // legal, exact match, return B* d->foo(b); // legal, exact match, return B* d->foo(d); // legal, D::foo((B*)d), return B*, ignore B::foo(D*) e->foo(b); // legal, exact match, return D* e->foo(d); // legal, E::foo((B*)d), return D*, ignore B:foo(D*) } If any of you language lawyers can see a reason why this wouldn't work, or why it *shouldn't*, please let me know. As I see it, the two means of defining multiple functions with the same name, virtuals and overloading, ought to be reconciled, and strong typing relaxed just enough to allow true subtypes (derived objects that are extensible in every ways compatible with contexts in which base objects are used) to be defined. In implementation terms, overloading a virtual function would normally lead to the argument overloading being resolved at compile-time, and the virtual function selection being resolved at run-time. Any argument list that was ambiguous (e.g. more than one of the overloaded functions might be called once the complete argument list was known at runtime) would simply be another possibility in the lookup table, albeit with slightly more overhead. Trees of classes that did not have any overloaded virtual functions, or just none that survived until runtime, would not incur any extra overhead (a major C++ design goal, not to incur overhead unless a feature is used). Comments and flames are welcome. There may be some bugs in the above, since obviously I can't compile it... yet. :) Craig Hubley "...get rid of a man as soon as he thinks himself an expert." Craig Hubley & Associates------------------------------------Henry Ford Sr. craig@gpu.utcs.Utoronto.CA UUNET!utai!utgpu!craig craig@utorgpu.BITNET craig@gpu.utcs.toronto.EDU {allegra,bnr-vpa,decvax}!utcsri!utgpu!craig 28 First Avenue, Toronto, Ontario M4M 1W8 Canada Voice: (416) 466-4097 -- Craig Hubley "...get rid of a man as soon as he thinks himself an expert." Craig Hubley & Associates------------------------------------Henry Ford Sr. craig@gpu.utcs.Utoronto.CA UUNET!utai!utgpu!craig craig@utorgpu.BITNET craig@gpu.utcs.toronto.EDU {allegra,bnr-vpa,decvax}!utcsri!utgpu!craig