Menu

Saturday, 4 July 2015

OBJECTS AND CLASSES

Object oriented programming (OOP) is a particular conceptual approach to designing programs, and C++ has enhanced C with features that ease the way to applying that approach. The most important OOP features are these:

  • Abstraction
  • Encapsulation and data hiding
  • Polymorphism
  • Inheritance
  • Reusable code

The class is the single most important C++ enhancement for implementing these features and tying together.

3.1 Procedural and Object-Oriented Programming:

Although we have explored the OOP perspective on programming ever so often, we've usually stuck pretty close to the standard procedural approach of languages such as C, Pascal, and BASIC. Let's look at an example that clarifies how the OOP outlook differs from that of procedural programming.  You first concentrate on the procedures you will follow and then think about how to represent the data. You begin by thinking about the data. Furthermore, you think about the data not only in terms of how to represent it, but also in terms of how it's to be used. You concentrate on the object, as the user perceives it, thinking about the data you need to describe the object and the object and the operations that will describe the user’s interaction with the data.  After you develop a description of that interface, you move on to decide how to implement the interface and data storage.  Finally, you put together a program to use your new design.

 

Abstraction: Abstraction is the crucial step of representing information in terms of its interface with the user. That is, you abstract the essential operational features of a problem and express a solution in those terms. The interface describes how the user initializes, updates, and displays the data.  From abstraction, it is a short step to the user-defined type, which in C++ is a class design that implements that interface.

 

Class: The class is the C++ vehicle for translating an abstraction to a user-defined type.  It combines data representation and methods for manipulating that data into one neat package. An object has the same relationship to a class that a variable has to a data type. An object is said to be an instance of a class, in the same way my 1954 Chevrolet is an instance of a vehicle. A class is a way to bind the data and its associated functions together. It allows the data (and functions) to be hidden, if necessary, from external use. When defining a class, we are creating a new abstract data type that can be treated like any other built-in data type.

Generally, a class specification has two parts:

1. Class declaration
2. Class function definitions
The class declaration describes the type and scope of its members. The class function definitions describe how the class functions are implemented.
The general form of a class declaration is:

class  class_name
{
            private:
variable declarations;
function declarations;
public:
variable declarations;
function declarations;
};

The class declaration similar to struct declaration. The keyword class specifies that what follows is an abstract data of type class_name.  The body of a class is enclosed within braces and terminated by a semicolon. The class body contains the declaration of variables and functions.  These functions and variables are collectively called members.  They are usually grouped under two sections; namely, private and public to denote which members are private and which are public.  These keywords are known as visibility labels.

The members that have been declared as private can be accessed only from within the class. On the other hand, public members can be accessed from outside the class also.  The data hiding is the key feature of OOP. The use of the keyword private is optional.  By default, the members are private. Such a class is completely hidden from the outside world and does not serve any purpose.

The variables declared inside the class are known as data members and the functions are known as member functions. Only the member functions can have access to the private members and functions. However, the public members (both functions and data) can be accessed from outside the class.  The binding of data and functions together into a single class-type variable is referred to as encapsulation.

A Simple Class Example: A typical class declaration would look like:


class item
{
int number;      II variables declaration
float cost;        II private by default
public:
void getdata(int a, float b);     // functions declaration
void putdata(void);                 II using prototype
            }

We usually give a class some meaningful name, such as item. This name now becomes a new type identifier that can be used to declare instances of that class type. The class item contains two data members and two function members. The data members are private by default while both the functions are public by declaration. The function getdata( ) can be used to assign values to the member variables number and cost, and putdata( ) for displaying their values. These functions provide the only access to the data members from outside the class. This means that the data cannot be accessed by any function that is not a member of the class item. Note that the functions are declared, not defined. Actual function definitions will appear later in the program. The data members are usual private and the member function

3.2 Creating Objects:

Remember that the declaration of item as shown above does not define any objects of item but only specifies what they will contain. Once a class has been declared, we can create variables of that type by using the class name (like any other built-in type variable). For example,
item x;             II memory for x is created

creates a variable x of type item. In C++, the class variables are known as objects. Therefore, x is called an object of type item. We may also declare more than one object in one statement. Example:

item x, y, z;

The declaration of an object is similar to that of a variable of any basic type. The necessary memory space is allocated to an object at this stage. Note that class specification, like a structure, provides only a template and does not create any memory space for the objects.

Objects can also be created when a class is defined by placing their names immediately after the closing brace, as we do in the case of structures. That is, the definition

class item
{
   …………..
   …………..
   …………..
} x. y, z;

would create the objects x, y and z of type item. This practice is seldom followed because we would like to declare the objects close to the place where they are used.

3.3 Accessing Class Members:

The private data of a class can be accessed only through the member functions of that class. The main( ) cannot contain statements that access number and cost directly. The following is the format for calling a member function:

object -name. function-name( actual-arguments ) ;


For example, the function call statement
x.getdata(100,75.5);

is valid and assigns the value 100 to number and 75.5 to cost of the object x by implementing the getdata( ) function. The assignments occur in the actual function. Similarly, the statement
x.putdata( );

would display the values of data members. Remember, a member function can be invoked only by using an object (of the same class). The statement like
getdata(100,75.5);

has no meaning. Similarly, the statement
x.number = 100;

is also illegal. Although x is an object of the type item to which number belongs, the number (declared private) can be accessed only through a member function and not by the object directly. It may be recalled that objects communicate by sending and receiving messages. This is achieved through the member functions. For example,
x.putdata( );

sends a message to the object x requesting it to display its contents.

The objects can access a variable declared as public directly. Example:
class xyz
{
int x;
int y;
public
int z;
};
            …………
            …………
xyz p;
p.x = 0;            // error, x is private
p.z = 10           // OK, z is public
            …………
            …………

Note that the use of data in this manner defeats the very idea of data hiding and therefore should be avoided.

3.4 Defining Member Functions:


Member functions can be defined in two places:
* Outside-the class definition
* Inside the class definition

It is obvious that, irrespective of the place of definition, the function should perform the same task. Therefore, the code for the function body would be identical in both the cases. However, there is a subtle difference in the way the function header is defined

Outside the Class Definition: Member functions that are declared inside a class have to be defined separately outside the class. Their definitions are very much like the normal functions. They should have a function header and a function body.


An important difference between a member function and a normal function is that a member function incorporates a membership ‘identical label’ in the header. This label tells the compiler which class the function belongs to. The general form of a member function definition is:

return-type class-name : : function-name (argument declaration)
{

Function body

            }

The membership label class-name:: tells the compiler that the function function-name belongs to the class class-name. That is, the scope of the function is restricted to the class-name specified in the header line. The symbol:: is called the scope resolution operator.

For instance, consider the member functions getdata( ) and putdata( ) as discussed in the previous section. They may be coded as follows:

void item :: getdata(int a, float b)
{
number = a;
cost = b;
}

void item :: putdata(void)
{
cout << "Number :" << number << "\n";
cout<< "cost ." << cost << "\n";
}

Since these functions do not return any value, their return::type is void.

The member functions have some special characteristics that are often used in the program development.
* Several different classes can use the same function name. The 'membership label' will resolve their scope.
* Member functions can access the private data of the class. A non-member function cannot do so. (However, an exception to this rule is a friend function discussed later.)
* A member function can call another member function directly, without using the dot operator.

Inside the Class Definition: Another method of defining a member function is to replace the function declaration by the actual function definition inside the class.  For example, we could define the item class as follows:

            Class item
            {
            int number;
            float cost;
            public:
            void getdata(int a, float b)      // declaration

void  putdata(void)     // definition
{
cout << "Number :" << number << "\n";
cout << "cost ." << cost << "\n";
}
            };

When a function is defined inside a class, it is treated as an inline function.  Therefore all the restrictions and limitations that apply to an inline function are also applicable here.  Normally only small functions are defined inside the class definition.

#include<iostream.h
            class part
            {
            int mnumber;
            int partno;
            float cost;
            public:
            void getdata(int a, int b, float c)         // declaration
            {
                              mnumber=a;
                  partno=b;
      cost=c;
            }
void  putdata(void)     // definition
{
cout << "Number :" << mnumber << "\n";
cout << "partno :" << partno << "\n";
cout << "cost ." << cost << "\n";
}
            };
void main( )
{
part p1;            //  define object  of class part
p1.getdata(234, 3455,234.35);            // call member function
p1.putdata( );                                      // call member function
}

3.4 Objects as Data Types:

Another kind of entity C++ objects can represent is variables of a user-defined data type.

class distance
{
private:
int feet;
float inches;
public:
void setdist(int ft, float in)
{
feet = ft;
inches = in;
}
void getdist( )
{
cout << "\nEnter feet: "; cin >> feet;
cout << "Enter inches: "; cin >> inches;
}
void showdist( )
{
cout << feet << "\'-" << inches << '\"';
}
};

void main( )
{
Distance dist1, dist2;
dist1.setdist(11, 6.25);           
dist2.getdist( );
cout << "\ndist1 = ";
dist1.showdist( );
cout << "\ndist2 ";
dist2.showdist( );
}

In this program the class Distance contains two data items, feet and inches. Here the class Distance also has three member functions setdist( ), which uses arguments to set feet and inches; getdist ( ) which gets values for feet and inches from the user at the keyboard; and showdist( ) , which displays the distance in feet-and-inches format. The value of an object of class Distance can thus be set in either of two ways. In main ( ) we define two objects of class Distance dist1 and dist2. One is given a value using the setdist ( ) member function with the arguments 11 and 25, and the other is given a value that is supplied by the user.



3.5 Constructors:

 

C++ provides a special member function called the constructor, which enables an object to initialise itself when it is created.  This is known as automatic initialisation of objects. It also provides another member function called the destructor that destroys the objects when they are no longer required.

A constructor is a 'special' member function whose task is to initialise the objects of its class. It is special because its name is the same as the class name. The constructor is invoked whenever an object of its associated class is created. It is called constructor because it construct the values of data members of the class.

A constructor is declared and defined as follows: 

            // class with a constructor
            class integer
            {
                        int m, n;
                 public:
                        integer (void);                         // constructor declared
                        .......................
                        .......................
            };
           
            integer: : integer (void)           Il constructor defined
            {
                        m = a; n = a;
            }

When a class contains a constructor like the one defined above, it is guaranteed that an object created by the class will be initialised automatically. For example, the declaration

            integer int1;     // object int1 created

not only creates the object int1 of type integer but also initialises its data members m and n to zero. There is no need to write any statement to invoke the constructor function (as we do with the normal member functions). If a 'normal' member function is defined for zero initialisation, we would need to invoke this function for each of the objects separately. This would be very inconvenient, if there, if there are a large number of objects.

A constructor that accepts no parameters is called the default constructor. If no such constructor is defined, then the compiler supplies a default constructor. Therefore a statement such as
            A a;

invokes the default constructor of the compiler to create the object a. 

The constructor functions have some special characteristics:
  • They should be declared in the public section.
  • They are invoked automatically when the objects are created.
  • They do not have return types, not even void and therefore, they cannot return values.
  • They cannot be inherited, though a derived class can call the base class constructor.
  • Like other C++ functions, they can have default arguments.
  • Constructors cannot be virtual. We cannot refer to their addresses,
  • An object with a constructor (or destructor) cannot be used as a member of a union.
  • They make implicit calls to the operators new and delete when memory allocation is     required,

When a constructor is declared for a class, initialisation of the class objects becomes mandatory.

3.6 Parameterized Constructors:

The constructor integer ( ), defined above, initializes the data members of all the objects to zero. However, in practice it may be necessary to initialize the various data elements of different objects with different values when they are created. C++ permits us to achieve this objective by passing arguments to the constructor function when the objects are created. The constructors that can take arguments are called Parameterized constructors.  

The constructor integer ( ) may be modified to take arguments as shown below:
            class integer
            { 
                        int m, n;
            public:
                        integer (int x, int y);    // parameterized constructor
            };
            integer :: integer(int x, int y)
            {
                        m = x; n = y;
            }

When a constructor has been parameterized, the object declaration statement such as
            integer int1 ;

may not work. We must pass the initial values as arguments to the functions when an object is declared.

This can be done in two ways:
* By calling the constructor explicitly.
* By calling the constructor implicitly.


The following declaration illustrates the first method:

            integer int1 = integer(0, 100);             // explicit call

This statement creates an integer object int1 and passes the values 0 and 100 to it. The second is implemented as follows:

            integer int1(0, 100);                            //implicit call

This method, sometimes called the shorthand method, is used very often as it is shorter, looks better and is easy to implement. When the constructor is parameterized, we must provide appropriate arguments for the constructor.

3.7 Multiple Constructors In A Class:

So far we have used two kinds of constructors. They are:
            integer( );                                 // No arguments
            integer(int, int);                       // Two arguments

In the first case, the constructor itself supplies the data values and no values are passed by the calling program. In the second case, the function call passes the appropriate values from main ( ). C++ permits us to use both these constructors in the same class. For example, we could define a class as follows:

            class integer
            {
                        int m, n;
            public:
                        integer( ) {m = 0; n = 0;}        // constructor 1 .

                        integer(int a, int b)
                        {m = a; n = b;}                        //constructor 2            

            integer(integer & i)
                        {m = i.m; n = i.n;}                   // constructor 3
             };

This declares three constructors for an integer object. The first constructor receives no arguments, the second receives two integer arguments and the third receives one integer object as an argument. For example, the declaration

                        integer l1 ;

would automatically invoke the first constructor and set both m and n of l1 to zero. The statement
            integer I2 (20,40);

would call the second constructor which will initialize the data members m and n of I2 to 20 and 40 respectively.
Finally, the statement

            I3(l2);

would invoke the third constructor which copies the values of I2 into I3. That is, it sets the value of every data element of l3 to the value of the corresponding data element of 12. As mentioned earlier, such a constructor is called the copy constructor. The process of sharing the same name by two or more functions is referred to as function overloading. Similarly, when more than one constructor function is defined in a class, we say that the constructor is overloaded.

class counter
{
private:
unsigned int count;
public:
counter( )         { count = 0; }  // constructor
void inc_count( )         { count++; }    // increment counter.
int get_count      { return count; }
};
void main( )
{
count c1, c2;                            // define and initialize
cout<<”\nc1=”<<c1.get_count( );      //display
cout<<”\nc2=”<<c2.get_count( );
c1.inc_count( );           // increment c1
c2.inc_count( );           // increment c2
c2.inc_count( );           // increment c2
cout<<”\nc1=”<<c1.get_count( );      //display again
cout<<”\nc2=”<<c2.get_count( );
}

the counter class has one data count of type unsigned int. It has three member functions: counter( ), which is a constructor, inc_count( ), which adds 1 to count; and get_count( ) which returns the current value of count.

3.8 Destructors:

A destructor, as the name implies, is used to destroy the objects that have been created by a constructor. Like a constructor, the destructor is a member function whose name is the same as the class name but is preceded by a tilde. For example, the destructor for the class integer can be defined as shown below:

~integer( ) { }

A destructor never takes any argument nor does it return any value.  It will be invoked implicitly by the compiler upon exit from the program (or block or function as the case may be) to clean up storage that is no longer accessible. It is a good practice to declare destructors in a program since it release memory space for future use.
Whenever new is used to allocate memory in the constructors, we should use delete to free that memory. A destructor has the same name as the constructor (which is the same as the class name) but proceeded by a tilde. For example

class Tarzan
{
private:
            int data;
public:
            Tarzan( ) { data = 0; }             // constructor
            ~Tarzan( ) { }                          // destructor
}

The most common use of destructor is to deallocate memory that was allocated for the object by the constructor.

3.9 Objects as Function Arguments:

We can pass objects of the class as arguments to the function, just as any other data type variable.  Consider the program below, it demonstrate objects as function. 

# include<iostream.h>

class Distance
{
private:
int feet;
float inches;
public:
Distance ( ) {  }                       // constructor (no arguments)
Distance (int ft, float in)         // constructor (two args)
{ feet = ft; inches = in; }

void getdist( )                        
{
cout << "\n Enter feet: "; cin >> feet;
cout << "Enter inches: "; cin >> inches;
}
void showdist( )
{          cout << feet << "\,-" << inches << ‘\"';           }

void add_dist( Distance, Distance );              // declaration
};

void Distance::add_dist(Distance d2, Distance d3)
{
            inches = d2.inches + d3.inches;
feet = 0;

if(inches >= 12.0> {
inches -= 12.0;
feet++;
            }
feet += d2.feet + d3.feet;
}

void main( )
{
Distance dist1 , dist3;
Distance dist2(11, 6.25);
dist1.getdist( );
dist3.add-dist(dist1, dist2);

cout,<< "\ndist1 = "; dist1.showdist( );
cout << "\ndist2 = "; dist2.showdist( );
cout << "\ndist3 = "; dist3.showdist( );
}

This program starts with a distance set to an initial value, and adds to it a distance supplied by the user, to obtain the sum of the distances. It then displays all the three distances. The Distance objects dist1 and dist3 are created using the constructor that takes no argument, dist2 created using the constructor that takes two arguments. The two distances to be added dist1 and dist2 are supplied as arguments to add_dist( ). When a member function is called, it is given access to only one object: the object of which the function is a member. Consider the following statement

            dist3.add_dist(dist1, dist2);

The function can access dist1 and dist2, because they are supplied as arguments. It can also access dist3, because it is a member function of dist3 itself. Notice that the result is not returned by the function. The return type of add_dist( ) is void. The result is stored automatically in the dist3 object.

3.10 Returning Objects from Function:

We can return an object from the function as a return value, just as passing it as an argument. The program below illustrate this.

# include<iostream.h>

class Distance
{
private:
int feet;
float inches;
public:
Distance( )
{ feet = 0; inches = 0.0; }
Distance(int ft, float in)
{ feet = ft; inches = in; }

void getdist( )
{
cout <<”\nEnter feet: "; cin >> feet;
cout << "Enter inches: "; cin >> inches;
}
void showdist( )
{
cout << feet << "\’-" << inches << ‘\”’; }
           
Distance add-dist( Distance );
};

Distance Distance::add_dist(Distance d2)
{
Distance temp;
temp.inches = inches + d2.inches;

if(temp.inches >= 12.0)
{
temp.inches - = 12.0;
temp.feet = 1;
}
temp.feet + = feet + d2. feet;
}

void main( ) {
Distance dist1, dist3;
Distance dist2(11, 6.25);
dist1.getdist( );
dist3 = dist1.add-dist(dist2);

cout << "\ndist1 = ";
dist1.showdist( );
cout << "\ndist2 = ";
dist2.showdist( );
cout << "\ndist3 = ";
dist3.showdist( );
 }


Exercise:

  1. Create a class called time that has separate int member data for hours, minutes and seconds. One constructor should initialize this data to 0 and another should initialize it to fixed values. A member function should display it, in 11:59:59 format. The final member function should add two objects of type time passed as arguments. Write a program to implement this.

  1. Define a class to represent a bank account. Include the following members:
Data members:
Name, Account number, Type of account, Balance
Member functions:
To assign initial values, To deposit an amount, To withdraw an amount after checking the balance.

Write a program to test the class.