Diamond inheritance for custom classes and base class derived from TObject

Dear all,
I have a simple question.
I have a set of classes which inheriths one from another.
My Base class inheriths from TObject.
What i would like to be able to do is for each of the class, do something like:

Class->SaveAs("file.root");

Of
Class->Write(“item”) given a open TFile.

Here the test code you can use to reproduce the issue

File Classes.h

%%writefile MyClasses.h
#pragma once
#include <TObject.h>
#include <TString.h>
#include <TTree.h>

class ConfigHolder : public TObject{
  public:
    ConfigHolder() = default;
    virtual ~ConfigHolder() = default;
  private: 
    TString m_s1 = "a";
    TString m_s2 = "b";
    ClassDef(ConfigHolder,1);
} ;

class WeightHolder : virtual public ConfigHolder{
  public:
    WeightHolder() = default;
    virtual ~WeightHolder() = default;
    
  private: 
    TString m_s3 = "c";
    TString m_s4 = "d";
  ClassDef(WeightHolder,1);
};

class TupleHolder : virtual public ConfigHolder{
  public: 
    TupleHolder() = default;
    virtual ~TupleHolder() = default;
  private :
    TString m_s5 = "dsa";
    ClassDef(TupleHolder,1);
};

class CutHolder : public WeightHolder{
  public:
    CutHolder() = default;
    virtual ~CutHolder() = default;
  private : 
    TString m_s5 = "das";
    ClassDef(CutHolder,1);
};


class EventType : public CutHolder , public TupleHolder {
  public: 
    EventType() = default;
    virtual ~EventType() = default;
  private:
    TString m_s6 = "evttype";
    ClassDef(EventType,1);
};

File Linkdef.h

%%writefile Linkdef.h
#ifdef __CINT__
 
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;

#pragma link C++ nestedclasses;
#pragma link C++ defined_in "MyClasses.h";

#endif

Compile dictionaries with

!rootcint -f MyClasses_dict.C -c $(root-config --cflags) -p MyClasses.h Linkdef.h

Test exectuable for read-write

%%writefile simple.C
#include "MyClasses.h"
#include <TFile.h>
#include <iostream>

int main() {
    {
        EventType etype;
        TFile f("etype.root", "RECREATE");
        etype.Write("item");
    }
    {
        TFile f("etype.root");
        // EventType* q = dynamic_cast<EventType*>(f.Get("item"));
    }
}

Compile the code

!$(root-config --cxx) -g -O0 $(root-config --libs) $(root-config --cflags) $(root-config --ldflags) simple.C MyClasses_dict.C

Run the test.

./a.out

Thanks in advance
Renato

Hi Renato,

I do not understand what the problem/question is? :slight_smile: Nice instructions though!
An issue I see with this code is the usage of #pragma once: this is incompatible with the way in which ROOT organises payloads in dictionaries (in absence of clang modules for reflections). I would use include guards instead.

Cheers,
D

The problem is that when i try to run the test code i get segfault as soon as I try to save to disk one of the class up in the inheritance. Thebaseclass which inherits from tobject can be persified. All the others not and Don t understand why.

@Danilo the issue and the question is that ClassDef doesn t seems to work for the virtual public inheritances. If In the code I write a class directly inheriting from the ConfigHolder I can store it to root file without segfault. The issue aries when the inheritance is defined as virtual public. Do you see what I mean?

Hi,

but let’s take a step back here.
Why do you need to inherit from TObject?
Why do you need virtual inheritance?
Perhaps we need to simplify a bit the implementation.

Cheers,
D

The reason why I have the inheritance from Tobject is purely to be able to persist the objects in a Ttree.
The reason why I have this inheritance scheme is because the ConfigHolder defines the basics type and category of the analysis switchers: year of data taking polarity trigger category q2 bin electrons or muon mode and head of the decay chain.
All the previous are my private members of ConfigHolder.
Then for each combination of those I have 1 Ntuple I can read. Thus the easiest thing to include all privates from ConfigHolder identifying the type of data I am handling was to inherit from that class and let the Tuple Holder to read a Ttree and play with that.
Then we have the weights which has to be applied to each category and in different way. Thus the weight holder. Then the cut holder which for each category has its own cut database to use.
Finally to have a weighted cutted tuple I made the superclass EventType which can simultaneously access in 1 go to a given category tuple apply the weights and cut it.
Some cuts depends on the weight to apply thus the CutHolder inherits from Weight Hölder.
I fully agree this is not the way of using inheritance. In my case I just want to factorize the various aspects of splitting by category, use a weight and cut the tuple and use all of that together. If you think there can be a better layout to achieve the kind of structure I described I will be more than happy to give a try and refractor the structure.

Hi,

I’m not sure I fully understand what you want to do, but it seems that you don’t need to use a complicated inheritance scheme. Why not simply have the Cut, Tuple, and Weight classes as data members of the EventType class? This would greatly simplify your layout and should work unless you specifically need EventType to be polymorphic with the other classes.

Cheers,
Max

As an extra tip, note that a class does not need to inherit from TObject to be written to a TTree.

@eguiraud What is the requirement to be able to do Class.Write(“name”) and Tfile->Get(“name”)?

Having dictionaries (and having cling know about the dictionaries) should be enough.

P.S.
at least that’s as of ROOT version 6

@eguiraud so If I understand correctly it will suffice to have the ROOT_GENERATE_DICTIONARY for my classes with the proper LinkDef for the classes of interest. Within those class declaration do I still need the ClassDef or not?

@Danilo knows better than me, but I don’t think you need a ClassDef for I/O, only for some extra goodies

Hi,

if they inherit from TObject, they need a ClassDef. If they don’t they don’t need one but having one will make the persistification slightly faster. In general, in order to persistify objects, their class does not necessarily need to inherit from TObject.

Cheers,
D

Hi @Danilo
Thanks for replying in the weekend.
If I can ask:
How do you persify this object if it doesn’t inherit from Tobject? I mean the Write() method is stolen from Tobject as well as the Save As so I am wonder if to do what you said one has to write its own Write method.
Thanks in advance
Renato

Hi,

for example with the TFile::WriteObject template method.

Best,
D

Thanks a lot for the suggestions at the end, i get rid of the Diamond inheritance introducing a bit of overhead in copying the base class around and store them as private members and always inheriting from TObject

I still think that there are some issues inside ROOT generating dictionaries when you have some diamond-inheritance chain, but as written in several forum, if one has to go for this model, probably need to make a step back and re-thing the framework.

Thanks all for the help

Renato

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.