Hi Benoit, Benoit Revenu <revenu@iap.fr> wrote concerning [ROOT] multiple inheritance from TObject [Mon, 28 Apr 2003 18:02:09 +0200 (METDST)] ---------------------------------------------------------------------- > Dear Rooters, > > I want a class to inherit from 2 others classes inheriting from TObject. > I don't need this class to be in a dictionnary so that I DON'T get the > rootcint error message : > ------------------------- > Warning: multiple ambiguous inheritance TObject and C. Cint will not get > correct base object address > > I would like to do something like : > -------------------------------------------- > cat test.h: > -------------------------------------------- > #include "TMinuit.h" > #include "TObject.h" > > class A : public TMinuit > { > public: > A(){} > ~A(){} > int a; > ClassDef(A,1) > }; > > class B : public TObject > { > public: > B(){} > ~B(){} > int b; > ClassDef(B,1) > }; > > class C : public A, public B > { > public: > C(){} > //~C(){} > int c; > }; Whoa - that's asking for a whole slew of problems. What you have is an ambiguity in the inheritance: A A class A { public: int next; } \ / class B : public A { void f(int); void g(char); } B C class C : public A { void f(int); void g(float); } \ / class D : public B, public C { void h(); void i(); } D Now, the standard clearly says that D::h() { B::next = C::next; } is well-formed, while void D::h() { next = 0; } is ill-formed; the reason being that there's no way to know which `next' (B::next inherited from A, or C::next inherited from _another_ A) is to be assigned. Similar holds for member function lookup: Either the compiler must be able to resolve the member function by context (that is, via it's arguments), or you must explicitly qualify the member function name: void D::i() { A::f(1L); } // Well-formed void D::i() { f(1L); } // Ill-formed void D::i() { g('a'); } // Well-formed - calls A::g(char) void D::i() { g(42); } // Well-formed - calls B::g(float) This is exactly the reason for the error you get > ../src/test.h: In method `C::~C ()': > ../src/test.h:26: request for member `operator delete' is ambiguous Another way to get out of this conundrum, is to use virtual inheritance: A class A { public: int next; } / \ class B : virtual public A { void g(char); } B C class C : virtual public A { void g(float); } \ / class D : public B, public C { void h(); void i(); } D In this case, there's only _one_ (indirect) base object of class A, and void D::h() { next = 0; } // is well-formed However, virtual inheritance may imply a performance hit, as even more calls have to be resolved via the virtual table. All this is explained in excruciating detail in the ISO/IEC standard, section 10.1. Then there's the issue whether CINT supports virtual inheritance (I don't know the answer to that question - anyone?). My advice, would be to avoid the multiple inheritance in the first place for classes that you need I/O and interpretation capabilities. Perhaps containment will do the job, or perhaps some sort of indirection. In `pure' C++ you can also use templates to `customise' a class, an option which unfortunately isn't that well supported in CINT (as you have to explicitly make instances and dictionaries for those instances). In general, multiple inheritance is a very nifty feature of C++ that you can use to do all sorts of cool things, but it's tricky business and you need to keep it at a level where it's not really needed for the casual user. Hope that clears things up a bit. Yours, ___ | Christian Holm Christensen |_| | ------------------------------------------------------------- | | Address: Sankt Hansgade 23, 1. th. Phone: (+45) 35 35 96 91 _| DK-2200 Copenhagen N Cell: (+45) 24 61 85 91 _| Denmark Office: (+45) 353 25 305 ____| Email: cholm@nbi.dk Web: www.nbi.dk/~cholm | |
This archive was generated by hypermail 2b29 : Thu Jan 01 2004 - 17:50:11 MET