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