>> 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