WARNING: This documentation is not maintained anymore. Some part might be obsolete or wrong, some part might be missing but still some valuable information can be found there. Instead please refer to the ROOT Reference Guide and the ROOT Manual. If you think some information should be imported in the ROOT Reference Guide or in the ROOT Manual, please post your request to the ROOT Forum or via a Github Issue.
The light-weight TObject
class provides the default behavior and protocol for the objects in the ROOT system. Specifically, it is the primary interface to classes providing object I/O, error handling, inspection, introspection, and drawing. The interface to this service is via abstract classes.
Introspection, which is also referred to as reflection, or run time type identification (RTTI) is the ability of a class to reflect upon itself or to "look inside itself. ROOT implements reflection with the TClass
class. It provides all the information about a class, a full description of data members and methods, including the comment field and the method parameter types. A class with the ClassDef
macro has the ability to obtain a TClass
with the IsA
method.
It returns a TClass
. In addition, an object can directly get the class name and the base classes by:
If the class is a descendent of TObject
, you can check if an object inherits from a specific class, you can use the InheritsFrom
method. This method returns kTrue
if the object inherits from the specified class name or TClass
.
ROOT and Cling
rely on reflection and the class dictionary to identify the type of a variable at run time. With TObject
inheritance come some methods that use Introspection to help you see the data in the object or class. For instance:
obj->Dump(); // lists all data members and their current values
obj->Inspect(); // opens a window to browse data members
obj->DrawClass(); // Draws the class inheritance tree
For an example of obj->Inspect()
, see “Inspecting Objects”.
To store an object in a ROOT collection, it must be a descendent of TObject
. This is convenient if you want to store objects of different classes in the same collection and execute the method of the same name on all members of the collection. For example, the list of graphics primitives are in a ROOT collection called TList
. When the canvas is drawn, the Paint
method is executed on the entire collection. Each member may be a different class, and if the Paint
method is not implemented, TObject::Paint
will be executed.
The TObject::Write
method is the interface to the ROOT I/O system. It streams the object into a buffer using the Streamer
method. It supports cycle numbers and automatic schema evolution. See “Input/Output”.
These graphics methods are defaults; their implementation in TObject
does not use the graphics subsystem. The TObject::Draw
method is simply a call to AppendPad
. The Paint
method is empty. The default is provided so that one can call Paint
in a collection. The method GetDrawOption
returns the draw option that was used when the object was drawn on the canvas. This is especially relevant with histograms and graphs.
Two useful methods are Clone
and DrawClone
. The Clone
method takes a snapshot of the object with the Streamer
and creates a new object. The DrawClone
method does the same thing and in addition draws the clone.
This method is called if the object is browse-able and is to be displayed in the object browser. For example the TTree
implementation of Browse
, calls the Browse method for each branch. The TBranch::Browse
method displays the name of each leaf. For the object’s Browse
method to be called, the IsFolder()
method must be overridden to return true. This does not mean it has to be a folder, it just means that it is browse-able.
This method is called by a canvas on its list of primitives, when the canvas is saved as a script. The purpose of SavePrimitve
is to save a primitive as a C++ statement(s). Most ROOT classes implement the SavePrimitive
method. It is recommended that the SavePrimitive
is implemented in user defined classes if it is to be drawn on a canvas. Such that the command TCanvas::SaveAs(Canvas.C)
will preserve the user-class object in the resulting script.
This method is called when displaying the event status in a canvas. To show the event status window, select the Options
menu and the EventStatus
item. This method returns a string of information about the object at position (x, y). Every time the cursor moves, the object under the cursor executes the GetObjectInfo
method. The string is then shown in the status bar. There is a default implementation in TObject
, but it is typically overridden for classes that can report peculiarities for different cursor positions (for example the bin contents in a TH1).
By default an object inheriting from TObject
is not brows-able, because TObject::IsFolder()
returns kFALSE
. To make a class browse-able, the IsFolder
method needs to be overridden to return kTRUE
. In general, this method returns kTRUE
if the object contains browse-able objects (like containers or lists of other objects).
A TObject
descendent inherits two data members: fBits
and fUniqueID
. fBits
is 32-bit data member used with a bit mask to get object information. Bits 0 - 13 are reserved as global bits, bits 14 - 23 can be used in different class hierarchies.
enum EObjBits {
kCanDelete = BIT(0), // if can be deleted
kMustCleanup = BIT(3), // if destructor must call RecursiveRemove()
kObjInCanvas = BIT(3), // for backward compatibility only
kIsReferenced = BIT(4), // if referenced by TRef or TRefArray
kHasUUID = BIT(5), // if has a TUUID, fUniqueID=UUIDNumber
kCannotPick = BIT(6), // if cannot be picked in a pad
kNoContextMenu = BIT(8), // if does not want a context menu
kInvalidObject = BIT(13) // object ctor succeeded but the object should not be used
};
For example, the bits kMustCleanup
and kCanDelete
are used in TObject
. See “The kCanDelete Bit” and “The kMustCleanup Bit”. They can be set by any object and should not be reused. Make sure not to overlap them in any given hierarchy. The bit 13 (kInvalidObject
) is set when an object could not be read from a ROOT file. It will check this bit and will skip to the next object on the file.
The TObject
constructor initializes the fBits
to zero depending if the object is created on the stack or allocated on the heap. When the object is created on the stack, the kCanDelete
bit is set to false to protect from deleting objects on the stack. The high 8 bits are reserved for the system usage; the low 24 bits are user settable. fUniqueID
is a data member used to give a unique identification number to an object. It is initialized to zero by the TObject
constructor. ROOT does not use this data member. The two data members (fBits
and fUniqueID
) are streamed out when writing an object to disk. If you do not use them, you can save some space and time by specifying:
This sets a bit in the TClass
object. If the file is compressed, the savings are minimal since most values are zero; however, it saves some space when the file is not compressed. A call toIgnoreTObjectStreamer
also prevents the creation of two additional branches when splitting the object. If left alone, two branches called fBits
and fUniqueID
will appear.
If you want to integrate and use your classes with ROOT, to enjoy features like, extensive RTTI (Run Time Type Information) and ROOT object I/O and inspection, you have to add the following line to your class header files:
For example in TLine.h
we have:
The ClassVersionID
is used by the ROOT I/O system. It is written on the output stream and during reading you can check this version ID and take appropriate action depending on the value of the ID. See “Streamers”. Every time you change the data members of a class, you should increase its ClassVersionID
by one. The ClassVersionID
should be >=1
. Set ClassVersionID=0
in case you don’t need object I/O. To be able to generate properly documentation for your classes using THtml
you must add the statement:
For example in TLine.cxx
:
Note that you should provide a default constructor for your classes, i.e. a constructor with zero parameters or with one or more parameters all with default values in case you want to use object I/O. If do not provide such a default constructor, you MUST implement an I/O constructor. If not you will get a compile time error. See the “The Default Constructor” paragraph in this chapter. The ClassDef
and ClassImp
macros are defined in the file Rtypes.h
. This file is referenced by all ROOT include files, so you will automatically get them if you use a ROOT include file.
In ROOT version 3.03 and older, ROOT provided special ClassDef
and ClassImp
macros for classes with two and three template arguments. In ROOT version 3.04 and above, the macros ClassDef
and ClassImp
can be used directly even for a class template. ClassImp
is used to register an implementation file in a class. For class templates, the ClassImp
can only be used for a specific class template instance.
For multiple template arguments, you will need to use an intermediary typedef
:
You can also register an implementation for all instances of a class template by using templateClassImp
:
Here are examples of a header and a LinkDef
file:
// in header file MyClass.h
template <typename T> class MyClass1 {
private:
T fA;
...
public:
...
ClassDef(MyClass1,1)
};
template <typename T1, typename T2> class MyClass2 {
private:
T1 fA;
T2 fB;
public:
...
ClassDef(MyClass2,1)
};
template <typename T1, typename T2, typename T3> class MyClass3 {
private:
T1 fA;
T2 fB;
T3 fC;
...
public:
...
ClassDef(MyClass3,1)
};
// A LinkDef.h file with all the explicit template instances
// that will be needed at link time
#ifdef __CLING__
#pragma link C++ class MyClass1<float>+;
#pragma link C++ class MyClass1<double>+;
#pragma link C++ class MyClass2<float,int>+;
#pragma link C++ class MyClass2<float,double>+;
#pragma link C++ class MyClass3<float,int,TObject*>+;
#pragma link C++ class MyClass3<float,TEvent*,TObject*>+;
#endif
ROOT object I/O requires every class to have either a default constructor or an I/O constructor. A default constructor is a constructor with zero parameters or with one or more parameters all with default values. An I/O constructor is a constructor with exactly one parameter which type is a pointer to one of the type marked as an ‘io constructor type’. We will come back to this context in a few paragraphs. This default or I/O constructor is called whenever an object is being read from a ROOT database. Be sure that you do not allocate any space for embedded pointer objects in this constructor. This space will be lost (memory leak) while reading in the object. For example:
class T49Event : public TObject {
private:
Int_t fId;
TCollection *fTracks;
...
public:
// Error space for TList pointer will be lost
T49Event() { fId = 0; fTrack = new TList; }
// Correct default initialization of pointer
T49Event() { fId = 0; fTrack = 0; }
...
};
The memory will be lost because during reading of the object the pointer will be set to the object it was pointing to at the time the object was written. Create the fTrack
list when you need it, e.g. when you start filling the list or in a not-default constructor.
The constructor actually called by the ROOT I/O can be customized by using the rootcling pragma:
For example, with this pragma and a class named MyClass, the ROOT I/O will call the first of the following 3 constructors which exists and is public:
MyClass(UserClass*);MyClass(TRootIOCtor*);
MyClass(); // Or a constructor with all its arguments defaulted.
When more than one pragma ioctortype is used, the first seen as priority. For example with:
We look for the first existing public constructor in the following order:
MyClass(UserClass1*);
MyClass(UserClass2*);
MyClass(TRootIOCtor*);
MyClass(); // Or a constructor with all its arguments defaulted.
A way in which dictionaries can be generated is via the rootcling
utility. This tool generates takes as input a set of headers and generates in output the dictionary C++ code and a pcm
file. This latter file is fundamental for the correct functioning of the dictionary at runtime. It should be located in the directory where the shared library is installed in which the compiled dictionary resides.
NOTA BENE: the dictionaries that will be used within the same project must have unique names. In other words, compiled object files relative to dictionary source files cannot reside in the same library or in two libraries loaded by the same application if the original source files have the same name. This loose limitation is imposed by the registration mechanism ROOT has in place to keep track of dynamically loaded libraries.
In the following example, we walk through the steps necessary to generate a dictionary, I/O, and inspect member functions. Let’s start with a TEvent
class, which contains a collection of TTracks
.
The TEvent.h
header is:
#ifndef __TEvent__
#define __TEvent__
#include "TObject.h"
#include "TCollection.h"
class TTrack;
class TEvent : public TObject {
private:
Int_t fId; // event sequential id
Float_t fTotalMom; // total momentum
TCollection *fTracks; // collection of tracks
public:
TEvent() { fId = 0; fTotalMom = 0; fTracks = nullptr; }
TEvent(Int_t id);
~TEvent();
void AddTrack(TTrack *t);
Int_t GetId() const { return fId; }
Int_t GetNoTracks() const;
void Print(Option_t *opt="");
Float_t TotalMomentum();
ClassDef(TEvent,1); //Simple event class
};
#endif
The things to notice in these header files are:
The usage of the ClassDef
macro
The default constructors of the TEvent
and TTrack
classes
Comments to describe the data members and the comment after the ClassDef
macro to describe the class
These classes are intended for you to create an event object with a certain id, and then add tracks to it. The track objects have a pointer to their event. This shows that the I/O system correctly handles circular references.
The TTrack.h
header is:
#ifndef __TTrack__
#define __TTrack__
#include "TObject.h"
class TEvent;
class TTrack : public TObject {
private:
Int_t fId; //track sequential id
TEvent *fEvent; //event to which track belongs
Float_t fPx; //x part of track momentum
Float_t fPy; //y part of track momentum
Float_t fPz; //z part of track momentum
public:
TTrack() { fId = 0; fEvent = nullptr; fPx = fPy = fPz = 0; }
TTrack(Int_t id, TEvent *ev, Float_t px,Float_t py,Float_t pz);
Float_t Momentum() const;
TEvent *GetEvent() const { return fEvent; }
void Print(Option_t *opt="");
ClassDef (TTrack,1); //Simple track class
};
#endif
Next is the implementation of these two classes.
TEvent.cxx
:
#include <iostream.h>
#include "TOrdCollection.h"
#include "TEvent.h"
#include "TTrack.h"
ClassImp(TEvent)
...
TTrack.cxx:
#include <iostream.h>
#include "TMath.h"
#include "TTrack.h"
#include "TEvent.h"
ClassImp(TTrack)
...
Now using rootcling
we can generate the dictionary file.
Looking in the file eventdict.cxx
we can see, theStreamer()
andShowMembers()
methods for the two classes. Streamer()
is used to stream an object to/from a TBuffer
and ShowMembers()
is used by the Dump()
and Inspect()
methods of TObject
. Here is the TEvent::Streamer
method:
void TEvent::Streamer(TBuffer &R__b)
{
// Stream an object of class TEvent.
UInt_t R__s, R__c;
if (R__b.IsReading()) {
Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }
TObject::Streamer(R__b);
R__b >> fId;
R__b >> fTotalMom;
R__b >> fTracks;
R__b.CheckByteCount(R__s, R__c, TEvent::IsA());
} else {
R__c = R__b.WriteVersion(TEvent::IsA(), kTRUE);
TObject::Streamer(R__b);
R__b << fId;
R__b << fTotalMom;
R__b << fTracks;
R__b.SetByteCount(R__c, kTRUE);
}
}
The TBuffer
class overloads the operator<<()
and operator>>()
for all basic types and for pointers to objects. These operators write and read from the buffer and take care of any needed byte swapping to make the buffer machine independent. During writing, the TBuffer
keeps track of the objects that have been written and multiple references to the same object are replaced by an index. In addition, the object’s class information is stored. TEvent
and TTracks
need manual intervention. Cut and paste the generated Streamer()
from the eventdict.cxx
into the class’ source file and modify as needed (e.g. add counter for array of basic types) and disable the generation of the Streamer()
when using the LinkDef.h
file for next execution of rootcling
. In case you do not want to read or write this class (no I/O) you can tell rootcling
to generate a dummy Streamer()
by changing this line in the source file:
If you want to prevent the generation of Streamer()
, see the section “Adding a Class with a Shared Library”.
Usually, headers are passed to rootcling at the command line. To generate a dictionary for a class from the STL, e.g.
std::vector<MyClass>, you would normally pass the header defining MyClass and std::vector. The latter is a compiler specific header and cannot be passed to rootcling directly. Instead, create a little header file that includes both headers, and pass that to rootcling.
Often ROOT knows where MyClass and the templated class (e.g. vector) are defined, for example because the files got #included. Knowing these header files ROOT can automatically generate the dictionary for any template combination (e.g. vector<myClass>) when it is needed, by generating files starting with AutoDict*. You can toggle this feature on or off at the ROOT prompt by executing .autodict.
Step 1: Define your own class in SClass.h
and implement it in SClass.cxx
. You must provide a default constructor or an I/O constructor for your class. See the “The Default Constructor” paragraph in this chapter.
#include <iostream.h>
#include "TObject.h"
class SClass : public TObject {
private:
Float_t fX; //x position in centimeters
Float_t fY; //y position in centimeters
Int_t fTempValue; //! temporary state value
public:
SClass() { fX = fY = -1; }
void Print() const;
void SetX(float x) { fX = x; }
void SetY(float y) { fY = y; }
ClassDef(SClass, 1)
};
Step 2: Add a call to the ClassDef
macro to at the end of the class definition (in the SClass.h
file). ClassDef(SClass,1)
. Add a call to the ClassImp
macro in the implementation file (SClass.cxx
): ClassImp(SClass)
.
// SClass.cxx:
#include "SClass.h"
ClassImp(SClass);
void SClass::Print() const {
cout << "fX = " << fX << ", fY = " << fY << endl;
}
You can add a class without using the ClassDef
and ClassImp
macros; however, you will be limited. Specifically the object I/O features of ROOT will not be available to you for these classes. See “Cling the C++ Interpreter”. The ShowMembers
and Streamer
method, as well as the >>
operator overloads, are implemented only if you use ClassDef
and ClassImp
. See $ROOTSYS/include/Rtypes.h
for the definition of ClassDef
and ClassImp
. To exclude a data member from the Streamer
, add a !
as the first character in the comments of the field:
Step 3: The LinkDef.h
file tells rootcling
which classes should be added to the dictionary.
Three options can trail the class name:
-
: tells rootcling
not to generate the Streamer
method for this class. This is necessary for those classes that need a customized Streamer
method.!
: tells rootcling
not to generate the operator>>(
TBuffer
&b,MyClass *&obj)
method for this class. This is necessary to be able to write pointers to objects of classes not inheriting from TObject
.#pragma link C++ class SClass!; // no >> operator
// or
#pragma link C++ class SClass-!; // no streamer, no >> operator
rootcling
to generate a Streamer
with extra byte count information. This adds an integer to each object in the output buffer, but it allows for powerful error correction in case a Streamer
method is out of sync with data in the file. The +
option is mutual exclusive with both the -
and !
options.IMPORTANT NOTE: In ROOT Version 3 and later, a “+” after the class name tells rootcling
to use the new I/O system. The byte count check is always added. The new I/O system has many advantages including support automatic schema evolution, full support for STL collections and better run-time performance. We strongly recommend using it.
For information on Streamers
see “Input/Output”. To get help on rootcling
type on the UNIX command line: rootcling -h
When using template classes, the order of the pragma statements matters. For example, here is a template class Tmpl
and a normal class Norm
, which holds a specialized instance of a Tmpl
:
Then in Linkdef.h,
the pragma statements must be ordered by listing all specializations before any classes that need them:
// Correct Linkdef.h ordering
...
#pragma link C++ class Tmpl<int>;
#pragma link C++ class Norm;
...
And not vice versa:
In this case, rootcling
generates Norm::Streamer()
that makes reference to Tmpl<int>::Streamer()
. Then rootcling
gets to process Tmpl<int>
and generates a specialized Tmpl<int>::Streamer()
function. The problem is, when the compiler finds the first Tmpl<int>::Streamer()
, it will instantiate it. However, later in the file it finds the specialized version that rootcling
generated. This causes the error. However, if the Linkdef.h
order is reversed then rootcling
can generate the specialized Tmpl<int>::Streamer()
before it is needed (and thus never instantiated by the compiler).
The complete list of pragma statements currently supported by Cling is:
#pragma link [C|C++|off] all [class|function|global|typedef];
#pragma link [C|C++|off]
[class|struct|union|enum|namespace|protected][name];
#pragma link [C|C++|off] [global|typedef][name];
#pragma link [C|C++|off] [nestedclass|nestedtypedef];
#pragma link [C++|C|off|MACRO] function [name]<(argtypes)>;
#pragma link
[C++|C|off|MACRO] function [classname]::[name]<(argtypes)>;
#pragma link off all methods;
#pragma link [C|C++|off] defined_in [filename];
#pragma link
[C|C++|off] defined_in [class|struct|namespace] [name];
#pragma link [C|C++|off] all_function [classname];
#pragma link [C|C++|off] all_datamember [classname];
The [classname]
and the [name]
can also contain wildcards. For example:
This will request the dictionary for all the class whose name start with 'MyClass'
and are already known to Cling (class templates need to have already been instantiated to be considered).
This pragma statement turns on or off the dictionary generation for all classes, structures, namespaces, global variables, global functions and typedefs seen so far by Cling. Example:
// some C++ header definition
#ifdef __ROOTCLING__
// turns off dictionary generation for all
#pragma link off all class;
#pragma link off all function;
#pragma link off all global;
#pragma link off all typedef;
#endif
The next pragma statement selectively turns on or off the dictionary generation for the specified classs
, struct
, union
, enum
or namespace
:
The Dictionary of all public members of class and struct will be generated. If the ‘class+protected
’ flag is used, the dictionary for protected members will also be generated. However, dictionary for protected constructor and destructor will not be generated. This ’ class+protected
’ flag will help you only for plain protected member access, but not for virtual function resolution.
If you use the ‘namespace
’ flag, it is recommended to add also:
The behavior of ‘class
’, ‘struct
’ and ‘namespace
’ flag are identical. Example:
// some C++ header definition
#ifdef __ROOTCLING__
#pragma link off all class;
#pragma link C++ class A;
#pragma link C++ class B;
#pragma link C++ class C<int>;
#pragma link C++ class+protected D;
#pragma link C++ namespace project1;
#pragma link C++ nestedclass;
#pragma link C++ nestedtypedef;
#endif
The next pragma statement selectively turns on or off the dictionary generation for global variables and typedef.
Example:
// some C/C++ header definition
#ifdef __ROOTCLING__
#pragma link off all global;
#pragma link off all typedef;
#pragma link C++ global a;
#pragma link C++ typedef Int_t;
#endif
This pragma statement turns on the dictionary generation for nested classes and nested typedefs.
Example:
// some C/C++ header definition
#ifdef __ROOTCLING__
#pragma link off all global;
#pragma link off all typedef;
#pragma link C++ global a;
#pragma link C++ typedef Int_t;
#endif
The next pragma statements turn on or off the dictionary generation for the specified function(s) or member function(s). The list of arguments’ type is optional. If you omit argument types, all function with specified [name
] will be affected. If the list of arguments’ type is specified, only the function that has exactly same argument list will be affected.
#pragma link [C++|C|off|MACRO] function [fname]<(argtypes)>;
#pragma link
[C++|C|off|MACRO] function [classname]::[fname]<(argtypes)>;
The ‘#pragma link [C++|C] function
’ and ‘#pragma link MACRO function
’ behaves similarly. The ‘#pragma link [C++|C] function
’ assumes the target to be a real function which has pointer to it. A pointer to registered function is registered. On the other hand, ‘#pragma link MACRO function
’ assumes target to be macro function. Pointer to function cannot be referenced in this case.
For the next example:
void f(int a);
void f(double a);
int g(int a,double b);
int g(double x);
#define max(a,b) (a>b?a:b)
class A {
public:
int h(double y);
int h(int a,double b);
};
The pragma statements are:
#ifdef __ROOTCLING__
#pragma link off all functions;
#pragma link C++ function f;
#pragma link C++ function g(int,double);
#pragma link C++ MACRO max;
#pragma link C++ class A;
#pragma link off function A::h(double);
#endif
Until Cling version 5.15.60, in order to generate dictionary for a member function, not only the member function but also the class itself has to be turned on for the linkage. There was an inconvenience when generating dictionary for template member function afterwards.
From Cling v.5.15.61, a new behavior is introduced. If link for a member function is specified, dictionary is generated even if link to the belonging class is off. For example, if you originally have A.h as follows:
And generate dictionary for that:
Then prepare another header file and instantiate the template member function of A.:
You can generate dictionary for the newly instantiated template member function only.
#ifdef __ROOTCLING__
#pragma link off defined_in A.h;
#pragma link C++ function A<int>::f(B&);
#endif
The next pragma turns off the dictionary generation of all the member functions in all classes.
Example:
The next pragma statements control the linking of all the member functions or data members for a specified class.
#pragma link [C|C++|off] all_function [classname];
#pragma link [C|C++|off] all_datamember [classname];
At this moment, there should be no needs to use those statements. Example:
See also: #pragma link function
.
The next pragma statement turns on/off dictionary generation of the object defined in specific file. The filename has to be the full pathname of the file.
Example:
// file1.h
// any C++ header definition
// file2.h
#ifdef __ROOTCLING__
#pragma link off all classes;
#pragma link off all functions;
#pragma link off all globals;
#pragma link off all typedef;
#pragma link C++ defined_in file1.h;
#endif
The next pragma statements turn on or off the dictionary generation of the object defined in a specific scope. The [scope_name
] should be class
name, struct
name or namespace
name. When using these pragmas, it is recommended to use also:
Otherwise, definitions in enclosed scope do not appear in the dictionary.
#pragma link [C|C++|off] defined_in [scope_name];
#pragma link [C|C++|off] defined_in
[class|struct|namespace] [scope_name];
Example:
The pragma statements are:
This statements controls default link mode for rootcling
.
By turning default ‘on’, all language constructs in given header files will be included in generated Cling dictionary (interface method source file). If default is set to ‘off’, nothing will be included in the generated dictionary. The next statement explicitly set linkage to each item:
This pragma statement must be given before rootcling
reads any C/C++ definitions from header files. Example:
#ifdef __ROOTCLING__
#pragma link default off;
#endif
class A {
int a;
double b;
};
class B {
int d;
double e;
};
#ifdef __ROOTCLING__
#pragma link C++ class A; // only class A is linked, not B
#endif
Step 4: Compile the class using the Makefile.
In the Makefile
call rootcling
to make the dictionary for the class. Call it SClassDict.cxx
. The rootcling
utility generates the methods Streamer
, TBuffer
&operator>>() and ShowMembers
for ROOT classes.
Load the shared library:
root[] .L SClass.so
root[] SClass *sc = new SClass()
root[] TFile *f = new TFile("Afile.root","UPDATE");
root[] sc->Write();
For more information on rootcling
see the $ROOTSYS/test
directory Makefile
, Event.cxx
, and Event.h
for an example, or follow this link: http://root.cern.ch/root/RootCintMan.html
Version 5 supported both Cint
and Reflex
dictionaries. The tool to create Reflex
dictionaries was a Python script called genreflex
and was very successful in the user community. Even if version 6 has only one type of dictionaries, cling
dictionaries, a re-implementation of genreflex
is provided. More precisely, in ROOT6, genreflex
is nothing but a wrapper around rootcling
, which offers an identical CLI and behaviour to the old Python tool. The input to genreflex
is a C++ header file, a set of switches and a selection XML file. The output, as for rootcling
, is a C++ dictionary source and a pcm
files. An exhaustive documentation of the CLI switches of genreflex
can be inspected with the genreflex --help
command.
The entity corresponding to the LinkDef
file for genreflex
is the selection XML file, also called selection XML or simply selection file. A selection XML file allows to describe a list of classes for which the dictionaries are to be created. In addition, it allows to specify properties of classes or data members, without the need to add comments in the source code. This is of primary importance when dictionaries must be created for classes residing in code which cannot be modified. For a complete description of the structure of the selection XML files and the way in which attributes can be set, refer to the genreflex --help
command.
It is important to observe that selection XML files can be used in presence of rootcling
invocations instead of LinkDef
files.
ROOT::Meta::Selection
namespaceNot only LinkDef
and selection
files allow to select the classes for which the dictionaries must be created: a third method is available. This is represented by the ROOT::Meta::Selection
namespace. The idea behind this technique is that all the classes which are located in this special namespace are automatically selected for dictionary generation. All the properties and annotations allowed by LinkDef
and selection XML
files are possible. For a detailed documentation of the features of the ROOT::Meta::Selection
namespace, refer to its online documentation.
Step 1: Define your class
#include "TObject.h"
// define the ABC class and make it inherit from TObject so that
// we can write ABC to a ROOT file
class ABC : public TObject {
public:
Float_t a, b, c, p;
ABC() : a(0), b(0), c(0), p(0){};
// Define the class for the dictionary
ClassDef (ABC,1)
};
// Call the ClassImp macro to give the ABC class RTTI and
// full I/O capabilities.
#if !defined(__CLING__)
ClassImp(ABC);
#endif
Step 2: Load the ABC class in the script.