Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!snorkelwacker.mit.edu!hsdndev!husc6!ngo From: ngo@tammy.harvard.edu (Tom Ngo) Newsgroups: comp.std.c++ Subject: Objects already contain type information => binary virtual functions Message-ID: Date: 28 Mar 91 14:36:48 GMT Sender: news@husc6.harvard.edu Distribution: comp Organization: Harvard Chemistry Department Lines: 75 Here's a wild idea whose purpose is to permit typesafe downcasts under certain circumstances. Do others think it's worth pursuing? Can it be generalized? The problem: class B { virtual void foo(B*); }; class D : public B { virtual void foo(D*); }; void bar(B* b1, B* b2) { b1.foo(b2); } D d1; D d2; bar(&d1,&d2); // I want D::foo to be invoked Currently, D::foo does not override B::foo. A way to cause this to happen is for D::foo to be declared D::foo(B*) and downcast B* to D* within the body of D::foo. This downcast is considered unsafe; see ARM p. 210-211. I call foo() a "binary" virtual function, meaning that the intention is for it to operate on two objects of identical type, even if the call is made with references or pointers to a base class of the type. I feel there is a strong need for such functions, and that currently there is no way to implement them that is both typesafe and elegant. For example, if you have a container class designed to take B*'s and you have given it all D*'s, the container class ought to be able to do things like compare objects in a D-specific manner, etc. Right now if you want to implement this sort of thing in a typesafe manner you have to make two separate virtual function calls, one for each operand of the comparison, or some such thing. The proposed solution: It has been argued that to implement typesafe downcasts would require that type information be added to each object. I suggest that objects already contain type information in their virtual function tables. So here's the idea: 1. Relax the requirement that two functions' arguments match EXACTLY for one to override the other. Instead, permit D::foo(D*) to match B::foo(B*). (In general, any argument of type D* or D* in the argument list of D::foo would match an argument of type B* or B* in B::foo.) 2. In that case, in D::foo(D* that) the compiler should automatically generate code that ensures: this->foo == that->foo (You know what I mean.) If the equality fails, then perhaps an addressing exception should be generated. This solution generalizes trivially to cases in which D::foo has several D* arguments. Comments? --Tom -- Tom Ngo ngo@harvard.harvard.edu 617/495-1768 lab number, leave message