Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!clyde.concordia.ca!uunet!microsoft!jimad From: jimad@microsoft.UUCP (Jim Adcock) Newsgroups: comp.lang.c++ Subject: Re: problem with virtual inheritence Message-ID: <11@microsoft.UUCP> Date: 19 Dec 89 00:10:47 GMT References: <952@sl10c.concurrent.co.uk> Reply-To: jimad@microsoft.UUCP (Jim Adcock) Organization: Microsoft Corp., Redmond WA Lines: 163 In article <952@sl10c.concurrent.co.uk> asc@concurrent.co.uk (Andy Chittenden) writes: >..... Thus if I use virtual inheritence, I must >reimplement my collection to be a collection of OtherWidgets. I have >thus lost a lot of my code reuse. > >Has anyone else discovered this problem and if so, have they found a way >out of it? /********* Regards generic container classes given virtual base classes -- I beleive the following approach is not too slimey. The idea is: 1) Make an empty non-virtual base class "Void" which classes to be containerized inherit off of as well as virtual base class "Object" [this is the most fundamental part of the trick] 2) Make helper classes of type "DirvRef", for each derived class "Dirv" where the function of "DirvRef" is to define explicetly what conversions are allowed. (For all classes to be containerized) 3) Make a generic container class based on VoidRef. 4) Derive class specific container classes from the generic container class to make sure you put a legitimate type of object in the container in the first place [alternately: make a polymorphic container and check types at run time. [bleh]] (Most of this code could be [hack] parameterized to reduce the amount of keystrokes involved) See Lippman pages 360-370 for a good explanation for virtual base classes. Remember, a virtual base class is *always* represented as a pointer to the shared data structure for the virtual base class. So converting some object to its virtual base class is an [acceptible] many-to-one relationship. Trying to convert back from a virtual base class to the containing object is an [unacceptible] one-to-many relationship. See Lippman's "Panda" example on page 367. *********/ #include #include "new.h" // foundation classes ------------------------------- typedef int handle; class Void { /* I'm empty, and I don't *do* 'anything' */ public: Void(); }; Void::Void(){} class Object { char* whoAmI; public: Object(char* id="Object"); virtual void Print() const { printf("%s\n", whoAmI); } }; Object::Object(char* id) { whoAmI = id; } class VoidRef { protected: Void* pvoid; public: VoidRef(); VoidRef(Void& obj); VoidRef(const VoidRef& obrefref); operator Void&() const { return *pvoid; } }; VoidRef::VoidRef(){pvoid = 0;} VoidRef::VoidRef(Void& obj) { pvoid = &obj; } VoidRef::VoidRef(const VoidRef& obrefref) { pvoid = obrefref.pvoid; } //pretend the Collection class is actually something substantial.... class Coll : private Void, public Object { //bogus, limit of 100, no checks. VoidRef ref[100]; VoidRef* pref; public: Coll(); handle Add(const VoidRef& new_member); VoidRef& operator[](handle position) const; }; handle Coll::Add(const VoidRef& new_member) { *pref++ = new_member; return pref-ref-1; } VoidRef& Coll::operator[](handle position) const { return ref[position]; } Coll::Coll() : Object("Coll") { pref = ref; } // application-oriented classes --------------------- class Widget : public Void, public Object { friend class WidgetRef; public: Widget(char* id="Widget"); }; Widget::Widget(char* id) : Object(id) {} class WidgetRef : public VoidRef { friend class Widget; public: WidgetRef(const Widget& widget); WidgetRef(const VoidRef& voidref); operator Widget&() const { return *(Widget*)pvoid; } }; WidgetRef::WidgetRef(const Widget& widget) : VoidRef((Void&)widget) {} WidgetRef::WidgetRef(const VoidRef& voidref) : VoidRef(voidref) {} class WidgetColl : public Coll { public: WidgetColl(); handle Add(const WidgetRef& widgetref) { return Coll::Add(widgetref); } WidgetRef operator[](handle position) const { return (Coll::operator[](position)); } }; WidgetColl::WidgetColl(){} class VBCWidget : public Void, public virtual Object { friend class VBCWidgetRef; public: VBCWidget(char* id="VBCWidget"); }; VBCWidget::VBCWidget(char* id) : Object(id) {} class VBCWidgetRef : public VoidRef { friend class VBCWidget; public: VBCWidgetRef(const VBCWidget& vbcwidget); VBCWidgetRef(const VoidRef& voidref); operator VBCWidget&() const { return *(VBCWidget*)pvoid; } }; VBCWidgetRef::VBCWidgetRef(const VBCWidget& vbcwidget) : VoidRef((Void&)vbcwidget) {} VBCWidgetRef::VBCWidgetRef(const VoidRef& voidref) : VoidRef(voidref) {} class VBCWidgetColl : public Coll { public: VBCWidgetColl(); handle Add(const VBCWidgetRef& vbcwidgetref) { return Coll::Add(vbcwidgetref); } VBCWidgetRef operator[](handle pos) const { return (Coll::operator[](pos)); } }; VBCWidgetColl::VBCWidgetColl(){} main() { Widget aWidget("aWidget"); WidgetColl aWidgetColl; handle aWidgetHandle = aWidgetColl.Add(aWidget); Widget& aWidgetRef = aWidgetColl[aWidgetHandle]; aWidgetRef.Print(); VBCWidget aVBCWidget("aVBCWidget"); VBCWidgetColl aVBCWidgetColl; handle aVBCWidgetHandle = aVBCWidgetColl.Add(aVBCWidget); VBCWidget& aVBCWidgetRef = aVBCWidgetColl[aVBCWidgetHandle]; aVBCWidgetRef.Print(); }