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:
- 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.
- 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.