Re: [ROOT] General questions

From: Matt Palmer (palmer@hep.phy.cam.ac.uk)
Date: Fri Dec 07 2001 - 19:12:14 MET


>> 2.  I made a simple little 3D viewer for some of my data (which was
>> impressively easy :) ).  However, I use TPolyLine3D to do the
>> drawing and I can't get any of the lines to be drawn in different
>> colours.   Currently I do  something like:

<snip>
>
>Use TPolyLine3D::SetLinecolor(Color_t);

D'oh! - Read the manual!
Thanks ;)


Warning the next bit has turned out a bit long and academic!

>> As a general point tho, I think I am right in saying that multiple
>> inheritance of non-pure virtual classes (ie non-interfaces) in
>> object hierachies with a single shared parent base class (ie
>> TObject) cannot work ...that's why it isn't allowed in Java, .NET
>> etc
>
>It will work if you have _virtual_ inheritance!  See also the ANSI/ISO
>C++ standard chapter 10.  Suppose you have
>
>  #include <iostream>
>  #ifdef USE_VIRTUAL
>  #define VIRTUAL virtual
>  #else
>  #define VIRTUAL
>  #endif
>
>  class A {
>    public:  virtual void f() { cout << "A:f" << endl; }};
>
>  class B : VIRTUAL public A {
>  #ifdef USE_OVERLOAD
>    public: virtual void f() { cout << "B::f" << endl; }
>  #endif
>  };
>
>  class C : VIRTUAL public A  {
>  #ifdef USE_OVERLOAD
>    public: virtual void f() { cout << "C::f" << endl; }
>  #endif
>  };
>
>  class D : public B, public C { };
>
>  int main()
>  {
>    D d;
>    d.f();
>    return 0;
>  }
>
>With USE_VIRTUAL undefined, it will not work, since you cannot find a
>unique calling sequence to A::f
>
>      A       A
>       \     /
>        B   C
>         \ /
>          D
>
>Compiling with GCC like
>
>  prompt% g++ foo.cxx -o foo
>  foo.cxx: In function `int main()':
>  foo.cxx:28: request for method `f' is ambiguous
>
>On the other hand, if we do define USE_VIRTUAL, it will work.
>
>  prompt% g++ foo.cxx -o foo -DUSE_VIRTUAL
>  prompt% ./foo
>  A:f
>
>This is because we now have for A::f
>
>          A
>         / \
>        B   C
>         \ /
>          D
>
>Now, if we define USE_OVERLOAD, then we get into trouble again:
>
>  prompt% g++ foo.cxx -o foo -DUSE_VIRTUAL -DUSE_OVERLOAD
>  foo.cxx: In function `int main()':
>  foo.cxx:27: cannot declare variable `d' to be of type `D'
>  foo.cxx:27:   since the following virtual functions need a final
> overrider: foo.cxx:27:         void B::f()
>  foo.cxx:28: request for method `f' is ambiguous
>
>So it seems C++ fares better than Java and .NET :-). Now, wether this
>would be a good strategy for ROOT classes to follow is an entirely
>different matter.

Hmm..interesting - I was unaware of this "feature".  It is potentially quite 
nice in that you can have interfaces with some implementation but you still 
have to be explicit as you do with an interface (ie all interface functions 
must be overloaded).  The writer of class D then has to explicitly choose 
which of the possible methods, B.F(), C.f(), A.f() if any to call in his 
D.f().  Having thought about this for a few moments, there are 3 problems 
that I can see with this:
1)       Both B and C have access to the public/protected data members of A.  
However, they are (programmatically) unaware of each other and have no 
imposed duty to access those members in a consistent way (particularly the 
protected ones).  This could cause problems eg suppose the writer of D wants 
to do something like:
f{
B.f();
C.f();
}  (pseudo-code)
which would be a prefectly reasonable thing to do.  But B.f() would leave a 
variable in A in a different state from C.f().  The code for D.f() then 
behaves very differently if it is instead 
f{
C.f();
B.f();
}
which is not obviously different. Indeed, one of the 2 possibilities may 
work, one may not - crashes etc are possible...its a potential minefield

2)       Consider the case where neither B or C override f - there is no 
problem 
and D does not have to override f either.  The writer of B then issues an 
update in which he does override f - maybe to fix a bug or provide additional 
functionality.  He thinks that this is fine because he hasn't changed the 
structure at all - he won't be breaking anyone's code.  He is unaware of C.  
The writer of D gets the update and thinks "great" and installs it thus 
breaking his software.

3)       In order for the writer of D to be able to override f() 
satisfactorily 
he will have to understand the details of the implementation of all of the 
versions of f() that are above D in the hierachy thus placing on him the 
burden of understanding someone else's code - assuming that code is even 
available - if it is distibuted compiled with headers then he may not be able 
to get access to the code at all.

Anyhow, that'll do for now - hope its understandable - it's probably a bit 
hastily thought about in places!

But, well, thanks for pointing that out - in a closed enviroment it could be 
useful.  But I think in more open enviroments, then it probably shouldn't be 
used! :)

Matt



This archive was generated by hypermail 2b29 : Tue Jan 01 2002 - 17:51:11 MET