[ROOT] Nested Class, I/O, ClassDef, and a hack to do it

From: Christian Holm Christensen (cholm@hehi03.nbi.dk)
Date: Wed May 09 2001 - 18:25:41 MEST


Hi ROOT'ers, 

I wanted to have a nested class Top::Nested that I could put in a
TClonesArray in the containing class Top.  If there's a way to do
this, and I've somehow overlooked it, I'm sorry about this rather long 
mail, and beesiege you to put it in the User's Guide (not in the one
from March 2001).  If there's no way to do it, then I'll hope you'll
take a look at this mail (and attached example) and maybe use it if
you see fit. 

However, coding away naiively like:

  class Top : public TObject {
  private: 
    int fN; 
    TClonesArray fArray;
  public:
    class Nested : public TObject { 
    private: 
      int fNested; 
      Nested(int nested=0) fNested(nested) {};
    
      ClassDef(Nested, 1) // Nested class
    };

    Top() : fN(0), fArray("Top::Nested",0) {}	
    void AddNested(int a) { new(fArray[fN++]) Nested(a); }
    Nested* GetNested(int i) { return (i >= fN || i < 0) ? 0 : fArray[i]; }

    ClassDef(Top, 1) // Class with nested class 
  };

  #pragma link C++ class Top+;
  #pragma link C++ class Top::Nested+; 

didn't go at all well.  The problem is the friend declaration 

   friend TBuffer &operator>>(TBuffer &buf, Nested *&obj);

in the expansion of ClassDef(Nested).  rootcint sees this as a friend
function called 

  TBuffer &Top::operator>>(TBuffer &buf, Top::Nested *&obj);

and makes a interface function for it, but G++ complains it can find
that function when compiling the dictionary files.  Incidently, I
believe there's no way to implement a function like that.  rootcint
creates 

  TBuffer &operator>>(TBuffer &buf, Top::Nested *&obj);

which is what you want, I believe.  I'm not sure what is the correct
way to do it, in terms of the ANSI/ISO Standard.  I looked it up, but
it wasn't clear to me what it said (Section 9.7, paragraph 4).
Someone more knowledgeable in the standard should investigate it. 

Anyway, so I poked around, and found a hack that I believe works. 

The trick is to define a macro ClassDef, and only have the troublesome 
line 

   friend TBuffer &operator>>(TBuffer &buf, Nested *&obj);

in the expansion if __CINT__ is not defined, as is the case in
rootcint.  Then I add an explicit external linkage declaration for 

  TBuffer &operator>>(TBuffer &buf, Top::Nested *&obj);

if __CINT__ _is_ defined, and explicitly in the linkdef file, tell
rootcint to create a interface function.  Finally, I ask CINT to
make method/member interfaces for nested classes as well, by adding
the line 

  #pragma link C++ nestedclass; 

in the linkdef file.  This last thing _is_ documented, and _not_ part
of the hack. 

Because I didn't get what the standard say about the naming scope of
friend functions declared in nested class, I don't know who's to blame
Masa or Rene and Fons :-) 

I hope you'll find this usefull, at least as small hint to a possible
solution. 

Yours, 

Christian  -----------------------------------------------------------
Holm Christensen                             Phone:  (+45) 35 35 96 91 
  Sankt Hansgade 23, 1. th.                  Office: (+45) 353  25 305 
  DK-2200 Copenhagen N                       Web:    www.nbi.dk/~cholm    
  Denmark                                    Email:       cholm@nbi.dk






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