Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!think.com!hsdndev!husc6!ngo From: ngo@tammy.harvard.edu (Tom Ngo) Newsgroups: comp.lang.c++ Subject: Seeking neat way to do binary "virtual" functions. Message-ID: Date: 19 Mar 91 16:40:16 GMT Sender: news@husc6.harvard.edu Distribution: comp Organization: Harvard Chemistry Department Lines: 117 I am looking for a pretty way to accomplish the following task, which must be fairly common. I have a base class B with publicly derived classes D1 and D2. And I have a class BHandler that handles homogeneous collections of B's, i.e. collections of B's which are either all D1 or all D2. BHandler causes B's to undergo certain virtual unary operations, i.e. ones that involve only one B. These are easy to implement. To sketch what I mean in case I'm being unclear: class B { void unary_op() =0; }; class D1 : public B { void unary_op(); } class BHandler { B *b0, *b1; void do_unary_op(); } void BHandler::do_unary_op() { b0->unary_op(); } Now my problem is, BHandler needs to make B's undergo binary operations, and I have been struggling to find a way to implement these in an elegant manner. Here are a few of the solutions I have found: (1) Cast B to D1 within a D1 member function: void BHandler::do_binary_op() { b0->binary_op(b1); } void D1::binary_op(B* that_) { D1 *that = (D1 *) that_; // do stuff with this and that } I don't like this solution very much because even though I know that_ can be converted to a D1*, the cast still seems dangerous. (2) Take advantage of the fact that the only truly safe way to convert a B* to a D1* is through a virtual function call: void BHandler::do_binary_op() { b1->operate_with(); b0->binary_op(); } D1::operate_with() { that = this; // then, that is a static member of D1, of type D1* } D1::binary_op() { // do stuff with this and that } This is even worse because in my application some calls to binary_op() need to be nested, so I still have to put a copy of that in an automatic variable, i.e. D1::binary_op() { D1* mythat = that; // do stuff with this and mythat } (3) The safest implementation I have thought of seems less error-prone but is somewhat cumbersome: class BHandler { B *b0, b1; void do_binary_op(); void provide_that(); } void BHandler::provide_that() { b1->is_that(); } class B { void is_that() =0; void request_that() =0; } class D1 : public B { D1 (BHandler* h_) : h(h_) {} BHandler* h; D1* that; static D1* static_that; void is_that() { static_that = this;} void request_that() { h->provide_that(); that = static_that; } void binary_op(); } void D1::binary_op() { request_that(); // do stuff with this and that } This is my favorite implementation because by merely glancing at the code one can tell it is safe... but at what cost? I would appreciate any suggestions. Do people consider this a fundamental limitation of C++, that the only way to safely convert a pointer to a class to a pointer to one of its derived classes is through a virtual function call? -- Tom Ngo ngo@harvard.harvard.edu 617/495-1768 lab number, leave message