TITLE: reference to derived is not to a base (Newsgroups: comp.lang.c++.moderated, 28 Aug 97) CLARK: Bill Clark > > Does anyone have experience with, or comments on, the idea of > combining the handle/body idiom with a dual inheritance > hierarchy? [snip] > suppose you also want to mirror, in the handle classes, the > inheritance relations among the body classes. So if you have > BBody derived from ABody, you want BHandle derived from AHandle. > This would allow you to pass a BHandle to a function expecting an > AHandle&, and all would work, just as it would have worked with > the body classes. EVERS: "Wil Evers" This is a serious but common mistake. In general, 'derived is-a base' does not imply 'derived handle is-a base handle', for the same reason that a pointer to a derived object is not a pointer to a base object. To see why, consider the following example: struct Base { }; struct Derived : Base { }; void f(Base*& bp); void h() { Derived *dp = new Derived; f(dp); // compiler error } This compiler error makes sense, because f() may modify the pointer passed to it by having it point to a Base object instead of a Derived object, thus violating the type system. While it is possible to convert the *value* of a pointer to a Derived to a pointer to a Base, it is not allowed to have an actual *object* of type 'pointer to Derived' stand in for an object of type 'pointer to Base'. Unless your handle objects can't be changed to refer to a different body object, this implies that, even though the body classes are related by inheritance, the relationship between the corresponding handle classes should not be expressed through inheritance. In such a case, you could consider a user-defined conversion instead, either by defining a conversion constructor in the base handle class: BaseHandle::BaseHandle(const DerivedHandle&); or by a conversion member function in the derived handle class: DerivedHandle::operator BaseHandle() const; This, of course, quickly becomes a hassle when your inheritance hierarchy is more than a few levels deep. If you have a compiler that supports member templates, you can use a member template to define a family of conversion constructors: template class Handle { Body *p; friend template class Handle; // any additional functionality... // ...(like reference counting) omitted public : template Handle(const Handle& rhs) : p(rhs.p) { } // ...other stuff elided... }; This will allow for the conversion of one handle class object to another, provided the language allows the corresponding conversion for built-in pointers.