next up previous contents index
Next: 13.3 Short Introduction to Up: 13. Object Oriented Computing Previous: 13.1 Introduction

Subsections


13.2 Objects and Encapsulation

In the model domain, the term object denotes the data representation of the objects of the problem domain, together with the operations defined on this data.

This means that we define a data structure together with the operations with it. These operations are usually called methods. The object's data are denoted as attributes; the data and methods together are denoted as members of the object.

A basic rule of OOP requires that the methods should be used for all the manipulations with object's data. Methods of the object are allowed to access the data; no other access is permitted. (We shall see that under some circumstances it is acceptable to violate this rule). This principle is called encapsulation and is sometimes presented by the ''wall of code around each piece of data'' metaphor.

Note:

Methods that return the value of the attribute (data member) X usually have the identifier GetX(); methods that set the value of the attribute X usually have the identifier SetX(). In some programming environments, these identifiers may be required. These methods are called getters and setters, respectively.

13.2.1 Benefits of Encapsulation

So far, there is nothing new in encapsulation: This is implementation hiding, well known from modular programming. The object may be considered as a module and the set of the methods as its interface.

The main benefit of encapsulation is that the programmer may change the implementation of the object without affecting the whole program, if he or she preserves the interface of the object. Any change of the data representation will affect only the implementation of the methods.

Example 2   Let's continue with the Monte Carlo simulation of the experiment with elementary particles. The object representing the detector will, of course, contain the coordinates of some important points of the detector. The first idea could be to use Cartesian coordinates; in later stage of the program development, it will be found that the spherical coordinates will suit better - e.g., because of the detector shape and program performance.

If it were allowed to manipulate the detector data directly by any part of the program, all the parts of the program that use this data should be changed. But if the encapsulation is properly applied and the data is manipulated only by the methods of the detector, all that has to be changed is the implementation of some detector methods.

13.2.2 Objects and Messages

OOP program is considered as the program consisting only of objects that collaborate by means of the messages. This may seem a little strange, but in this context, to send a message to an object means to call a method of this object. A message means a request for an operation on the object's data, i.e., a request to perform a method.

The object may receive only those messages for which it has corresponding methods. Sending a message that the object does not recognize causes an error. It depends on the programming language whether this error is detected in the compile time or in the run time. (In C++, it is detected in the compile time).

13.2.3 Class

Objects of problem domain may often be grouped into classes; one class contains objects that differ only in the values of some properties. The same holds for the objects in the model domain. The classes of objects in the problem domain are represented by user-defined data types in OOP programs called object types or classes.

The term instance is used to denote a variable, constant, or parameter of an object type. It is equivalent to the term object.

13.2.3.1 Class Members

Up to now, we have considered the class as a data type only; it serves as a template for the creation of instances. But in OOP, the class may have its own data and its own methods and may receive messages.

Data members that are part of the whole class (not of particular instances) are called class data members or class attributes and the methods that correspond to messages sent to the whole class are called class methods. Non-class members, attributes, as well as methods are, if necessary, denoted instance members.

Class data members contain data shared among all the instances of the class; class methods operate on class attributes. (From the non-OOP point of view, class data members are global variables hidden in the class, and class methods are global functions or procedures hidden in the class.)

Note:

Class data members are often called static data members and class methods are called static methods in C++, Java, and some other programming languages, because they are declared using the static keyword in these languages.

Note:

The class in C++, Java and many other OOP languages may contain definitions of other types, including other classes, as class members. Even though the so called nested classes are sometimes very useful, we will not discuss them in this article.

Note:

The class in the OOP may be considered as an instance of another class; this leads to the concept of metaclass. Metaclass is a class that has only one instance - a class. You can find metaclasses in pure OOP languages like Smalltalk. We will not discuss the concept of metaclass here.

Example 3   We may suppose - at some level of abstraction - that the representation of all the particles in the Monte Carlo simulation of the experiment with the particles is essentially the same. Thus, every individual particle belongs to the class of particles. It follows that the model will contain the Particle class, and the program will contain the definition of the corresponding data type (and of course some instances of this type).

Because every particle has its own mass and velocity, the Particle class will contain the declaration of four data items representing particle mass and three components of the particle velocity vector. The Particle class should also contain methods to set and to get the values of these data items. (Later on, we will see that even other methods are necessary - e.g., a method for the interaction with the detector.)

It is also necessary to know the total number of generated particles and the actual number of existing particles in the simulation program. These numbers of the particles do not describe an individual particle and so they cannot be data members of any Particle instance; it is the task of the whole Particle class to hold these data. So they will be stored in the class attributes (because we use the C++, we may say in static attributes) of type int, and they will be accessed by class methods (static methods).

Definition of the Particle class in C++ will be as follows:

// Particle class definition in C++, first approach
class Particle
{
public:
   // Constructor
   Particle(double _mass, double vX,
            double vY, double vZ);
   // Instance methods
   ~Particle() { --actual; }              // Destructor
   double GetMass() { return mass; }
   void SetMass(double m){ mass = m; }
   void SetVelocity(double vX, double vY, double vZ);
   double GetVelocityX() { return velocityX; }
   // Performs the interaction with the detector
   virtual void Interact(Detector *aDetector);
   // ... and other methods
   // Class methods
   static int GetActual() { return actual; }
   static int GetTotal() {}
private:
   // Instance data members
   double mass;
   double velocityX, velocityY, velocityZ;
   // Class data members
   static int actual;
   static int total;
};                   // End of the class declaration

// Definition of the static attributes
int Particle::actual = 0;
int Particle::total = 0;

// Definition of the constructor
Particle::Particle(double _mass, double vX,
                   double vY, double vZ)
: mass(_mass), velocityX(vX), velocityY(vY),
               velocityZ(vZ)
{
 ++actual; ++total;
}
// And other method definitions

We will not discuss the syntactic rules of the class declaration in the C++ here - this can be found in any textbook of this programming language, e.g., in [7]. We only note a few points.

This class contains the instance attributes mass, velocityX, velocityY, and velocityZ, and the class attributes actual and total (note the static keyword in their declarations). It follows that every instance of the Particle class will have its own data members mass, velocityX, etc. On the other hand, no instance will contain the data members total or actual. These are global variables shared by all instances and they exist even before the first instance of the Particle class is created and after the last one is destroyed.

The Particle() method is a special method called ''constructor'' and it serves the construction of new instances. It is invoked as a response to the message requesting the creation of a new instance of the class. (Even though it is a class method, its declaration in C++ does not contain the static keyword.) Its task is to initialize instance attributes. In our example, it also actualizes the values of the two class attributes.

The ~Particle() method is another special method called ''destructor'' that prepares the instance for decay. In our example, it decreases the number of existing particles, because the instance for which the destructor is called will be immediately destroyed. (This is - unlike the constructor - the instance method. Note, that in garbage collected OOP languages, e.g., in Java, destructors are not used.)


13.2.4 Object Composition

One object in a program may exploit the services of another object. It may call the methods of any other independent object, or it may contain another object as a data member. The second approach is usually called object composition, even though it is typically implemented as composition of the classes.

Note:

An object may not contain another object of the same class, of any class containing an object of the same class or of any derived class as data member. It may, of course, contain the pointers or the references to objects of any of these classes.

Example 4   Consider the particle source in the Monte Carlo simulation. It will be an instance of the Source class. For the simulation of the random processes of the emission of a particle, we will need a random number generator. The random number generator will be implemented in the program as an instance of the Generator class and will be based on the theory discussed in Chap. II.2. (The Generator class is an example of a class that has been found during the design of the Source class. It does not appear in the original formulation of the problem.)

This means that the Source class will contain an instance of the Generator class or a pointer to an instance of that class:

class Source
{
public:
   Source();
   Particle* Generate(); // Returns pointer to new
                            particle
   // ... and other methods
private:
   Generator *gen;
   // ... and other private members
};


13.2.5 Access Control

Note the private and public access specifiers in the class declarations above. The public specifier declares that all the subsequent members of the class are public, i.e., they are accessible from any part of the program. The public members of the class constitute the class interface. The class interface usually contains only some methods and constant attributes. (Constant attributes may be accessed directly. This does not violate the encapsulation, because constant attributes cannot be changed.)

The private specifier means that the following members of the class are private, i.e., accessible only from the methods of the class. In other words, private members are implementation details of the class that can not be used by other parts of the program. Changes of private parts of the class do not change the class interface and do not affect other parts of the program.

Later on, we will see the third access specifier, protected. Protected members are accessible only from the methods of this class and from all the derived classes. So, they constitute the class interface for derivation, that may be wider than the interface of the class for common use. We will discuss the inheritance in Sect. 13.4.

The access specifiers help to implement the encapsulation. Note that in C++, as well as in many other object oriented languages, the subject of access control is the class, not the individual objects (instances). So any method called for an instance of the given class may use all private members of another instance of the same class.


next up previous contents index
Next: 13.3 Short Introduction to Up: 13. Object Oriented Computing Previous: 13.1 Introduction