First Steps: Classes


Creating classes and objects.

The Lesson

So far in our lessons we have done nothing that cannot be done (some might say better) in FORTRAN. Its now time to create our first object. We will continue with the quadratic equation theme and turn it into a Quad object. When starting to think of objects the first questions to ask are:- We will answer these as follows:- We have now defined the interface to the Quad object and are ready to wrap it up in a class Quad { ... }; statement. Don't forget the trailing ; - a popular mistake for beginners!. Create the file:- Quad.h containing the following:- class Quad { public: Quad(Float_t a, Float_t b, Float_t c); Float_t Evaluate(Float_t x) const; void Solve() const; private: Float_t fA; Float_t fB; Float_t fC; }; All the public members are collected together as a set and presented first. This is standard practice; as users of an object only need to see the public part, they can stop as soon as they see the private keyword. Although it is not strictly necessary, you can check for errors by attempting to load the header:- .L Quad.h All that remains now is to define the constructor function Quad and the other two member functions Evaluate and Solve. This is done by creating a second file called Quad.cxx containing:- #include <iostream.h> #include <math.h> #include "Quad.h" Quad::Quad(Float_t a, Float_t b, Float_t c) { fA = a; fB = b; fC = c; } Float_t Quad::Evaluate(Float_t x) const { return fA*x*x + fB*x + fC; } void Quad::Solve() const { Float_t temp = fB*fB - 4.*fA*fC; if ( temp > 0. ) { temp = sqrt( temp ); cout << "There are two roots: " << ( -fB - temp ) / (2.*fA) << " and " << ( -fB + temp ) / (2.*fA) << endl; } else { if ( temp == 0. ) { cout << "There are two equal roots: " << -fB / (2.*fA) << endl; } else { cout << "There are no roots" << endl; } } } The first thing to notice is that user headers are placed in double quotes, unlike system ones that are surrounded by angle brackets. That's because compilers, including CINT look in different places for the two types of headers. The next thing to notice is that all 3 function names are now prefixed by Quad:: meaning that they are defined within the scope of the Quad class; this was implicit when the functions were declared within the class statement.

The constructor Quad::Quad initialises the data members. Quad::Solve returns a Float_t expression and Quad::Solve is based closely on the quad_eqn function of the Macros lesson. Load the code:-

.L Quad.cxx and if all is well we are ready to create Quad objects! The simplest way to do this is by typing something like:- Quad my_object(1.,2.,-3.); This creates a Quad object called my_object and initialises it. Its very similar to the declaration and initialisation of a built-in type:- Int_t num = 3; except that the assignment part is replaced by an argument list - this argument list is past to the Quad::Quad constructor. To make the parallel even closer, C++ permits built-in types to be initilialised the same way e.g.:- Int_t num(3); Any number of Quad objects can created in a similar way. We can ask our Quad object to calculate its roots by sending it its Solve message:-
We can evaluate our Quad object at some value of x, say 5.5, by
  Float_t y = my_object.Evaluate(5.5);
  cout << "Value of Quad at 5.5 is " << my_object.Evaluate(5.5) << endl;
The .print command can be used to print out the type of the object and the values of its data members:- .print my_object You can also ask CINT for details of the class using the .class command:- .class Quad Although CINT knows about our Quad class, ROOT in general does not. If you want ROOT to provide special services such as:- then there is a further step that has to be taken. This involves using CINT to build a dictionary for the class. This will not be covered in these First Steps but further information can be found Adding Your own Classes to ROOT

Our Quad example may seem a bit pointless, in part this is because the example has to be so trivial but also because a program with a single object is not an OO program. Its only when we assemble a set of objects that start to interact does the power of OO emerge. Never the less we have taken a first step towards OO. We have started to collect together everything we know about a quadratic form into a single piece of code. In principle we could collect together the definitive knowledge and then, forever more, when we needed a quadratic form we could reuse the code. Of course we could do this in a FORTRAN based program too. The power of an OO language like C++ is that a properly engineered class becomes an extension of the language allowing the object to be used wherever a built-in data type is allowed.


Go Back to the The First Steps Top Page

If you have any comments about this page please send them to Nick West