Path: utzoo!attcan!uunet!cs.utexas.edu!sdd.hp.com!ucsd!scripps!bashford From: bashford@scripps.edu (Don Bashford) Newsgroups: comp.lang.c++ Subject: Re: Multiple inheritance and type casting Message-ID: <588@riscsm.scripps.edu> Date: 9 Oct 90 19:34:53 GMT References: <5087@uqcspe.cs.uq.oz.au> <2709eabf.5abd@petunia.CalPoly.EDU> <5130@uqcspe.cs.uq.oz.au> Sender: news@Scripps.EDU Organization: Research Institute of Scripps Clinic; La Jolla, CA Lines: 86 In article <5130@uqcspe.cs.uq.oz.au> iain@batserver.cs.uq.oz.au writes: >rae@gpu.utcs.toronto.edu (Reid Ellis) writes: > >>I have found that casts lead to errors, plain and simple. If you are casting >>base types to derived types, something is wrong with your design. > > I don't agree. Take for example the overloading of operator==. If we > defined it as follows > inline operator == (Base &b1, Base &b2) { return b1.IsEqual (b2); } > where IsEqual is a virtual function declared in class Base. It's > prototype is > virtual int IsEqual (Base &); > > class Derived: public Base { > public: > virtual int IsEqual (Base &b) { return x == ((Derived &) b).x; } > private: > int x; > } > > We can then say things like > > Derived d1, d2; > > if ( d1 == d2 ) ... > > If I've missed something, and there is a more elegant solution to the > above scenario, please contribute. (Assume that we cannot declare > operator== as a virtual function in Base). > Here is a working example (tested with g++) that does what I think your example tries to do. Note that all the == and IsEqual machinery is defined in the Base class and that as long as the notion of "equalness" remains the same, the derived class can continue to use it thanks to the standard conversions under derivation (see Lippman, p. 319). #include class Base { private: int x; public: Base (int xv) : x(xv) {} int IsEqual (Base &b) {return x == b.x;} friend int operator == (Base &b1, Base &b2); }; int operator == (Base &b1, Base &b2) {return b1.IsEqual(b2);} class Derived : public Base { private: int y; public: Derived (int xv) : Base(xv) {} }; main () { Derived d1(4), d2(4), d3(5); cout << (d1 == d2) << "\n" << (d2 == d3) << "\n"; } > Now, any class derived from Base will probably want it's own version > of IsEqual, but because the formal parameter is a Base &, a cast to > the derived class will be required to compare attributes of the > derived class (for example). > If a derived class wants its own version of IsEqual then the notion of "equalness" must have changed, so it is quite natural that you should need to define a new set of functions such as Derived::IsEqual (Base &) Derived::IsEqual (Derived &) int operator == (Base &, Derived &) and so on. This might require making x a protected rather than private member of Base or providing an access function. As far as I can see, none of this requires the use of virtual functions. Function overloading is enough. Don Bashford bashford@scripps.edu