Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Chapter 5 OOP Using C++

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 15

Debremarkos University Department of Information Technology

CHAPTER FIVE
5. INTRODUCTION TO OBJECT ORIENTED PROGRAMMING USING C++

5.1. Basic Concepts of Object Oriented Programming


It is necessary to understand some of the concepts used extensively in object-oriented programming.
These include: Objects, Classes, Data abstraction, Inheritance and Polymorphism.
 Objects
Objects are the basic run time entities in an object-oriented system. They may represent a person, a
place, a bank account, a table of data or any item that the program has to handle. Programming problem
is analyzed in term of objects and the nature of communication between them. Program objects should
be chosen such that they match closely with the real-world objects. Objects take up space in the
memory and have an associated address like a record in Pascal, or a structure in C.
When a program is executed, the objects interact by sending messages to one another. For example, if
“customer” and “account” are objects in a program, then the customer object may send a message to the
account object requesting for the bank balance. Each object contain data, and code to manipulate data.
Objects can interact without having to know details of each other’s data or code. It is a sufficient to
know the type of message accepted, and the type of response returned by the objects.
 Classes
A class is a definition of objects of the same kind. In other words, a class is a blueprint, template, or
prototype that defines and describes the static attributes and dynamic behaviors common to all objects
of the same kind. The entire set of data and code of an object can be made a user-defined data type with
the help of class. In fact, objects are variables of the type class. Once a class has been defined, we can
create any number of objects belonging to that class.

A class can be visualized as a three-compartment box, as illustrated:


 Class name (or identifier): identifies the class.
 Data Members or Variables (or attributes, states, fields): contains the static attributes of the class.
 Member Functions (or methods, behaviors, operations): contains the dynamic operations of the
class.
In other words, a class encapsulates the static attributes (data) and dynamic behaviors (operations that
operate on the data) in a box.
Class Members: The data members and member functions are collectively called class members.

1|Page
Debremarkos University Department of Information Technology

A class is used to specify the form of an object and it combines data representation and methods for
manipulating that data into one neat package. The data and functions within a class are called members
of the class.

 C++ Class Definitions:


When you define a class, you define a blueprint for a data type. This doesn't actually define any data,
but it does define what the class name means, that is, what an object of the class will consist of and
what operations can be performed on such an object.
A class definition starts with the keyword class followed by the class name; and the class body,
enclosed by a pair of curly braces. A class definition must be followed either by a semicolon or a list of
declarations. For example, we defined the Box data type using the keyword class as follows:
class Box{
public:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
The keyword public determines the access attributes of the members of the class that follow it. A public
member can be accessed from outside the class anywhere within the scope of the class object. You can
also specify the members of a class as private or protected which we will discuss in a sub-section.

 Define C++ Objects:


A class provides the blueprints for objects, so basically an object is created from a class. We declare
objects of a class with exactly the same sort of declaration that we declare variables of basic types. The
following statements declare two objects of class Box:
Box Box1; // Declare Box1 of type Box
Box Box2; // Declare Box2 of type Box
Both of the objects Box1 and Box2 will have their own copy of data members.

 Accessing the Data Members:


The public data members of objects of a class can be accessed using the direct member access operator
(.). Let us try the following example to make the things clear:
#include <iostream.h>
class Box
{
public:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
int main( )
{
Box Box1; // Declare Box1 of type Box
Box Box2; // Declare Box2 of type Box
double volume = 0.0; // Store the volume of a box here

2|Page
Debremarkos University Department of Information Technology

// box 1 specification
Box1.height = 5.0;
Box1.length = 6.0;
Box1.breadth = 7.0;
// box 2 specification
Box2.height = 10.0;
Box2.length = 12.0;
Box2.breadth = 13.0;
// volume of box 1
volume = Box1.height * Box1.length * Box1.breadth;
cout << "Volume of Box1 : " << volume <<endl;
// volume of box 2
volume = Box2.height * Box2.length * Box2.breadth;
cout << "Volume of Box2 : " << volume <<endl;
return 0;
}
When the above code is compiled and executed, it produces the following result:
Volume of Box1 : 210
Volume of Box2 : 1560
It is important to note that private and protected members cannot be accessed directly using direct
member access operator (.). We will learn how private and protected members can be accessed.

 Defining member functions


Class member function can be defined inside the class or outside the class. If the member function of a
class is defined outside the class it follows the following form.
Return type ClassName :: member function(parameter list)
{
Statements;
}
Example
#include <iostream.h>
class CRectangle {
int x, y;
public:
void set_values (int,int);
int area (void)
{
return (x*y);
}//member definition inside the class
};
//define member function set_Values
void CRectangle::set_values (int a, int b)
{
x = a;
y = b;
}
int main ( )
{
CRectangle rect;

3|Page
Debremarkos University Department of Information Technology

rect.set_values (3,4);
cout << "area: " << rect.area( );
}

 Classes inside classes


A part from member data and member functions, classes can also define their own data types. These
new class definitions, inside the given class, can then be used by the class's member functions as well
as from outside the class. In the latter case, one has to use the scope operator. See the following
example for details.
#include <iostream.h>
class myclass
{
int a;
public:
class local_type
{
double t;
public:
local_type(double x)
{
t = x;
}
void print( )
{
cout << "Local type: " << t << endl;
}
};
void print( )
{
cout << a << endl;
}
};
int main( )
{
myclass::local_type z(2.3);
z.print( );
return 0;
}
Note that the same access restriction for member data and member functions also applies to classes
defined inside other classes. I.e. these classes can only be used from outside the class in which they
are defined, if they were declared as public.

5.2. Constructors and destructors


Objects generally need to initialize variables or assign dynamic memory during their process of creation
to become totally operative and to avoid returning unexpected values during their execution. For
example, what would happen if in the previous example (in class member definition) we called the
function area ( ) before having called function set values? Probably an undetermined result since the
members x and y would have never been assigned a value.

4|Page
Debremarkos University Department of Information Technology

In order to avoid that, a class can include a special function: a constructor, which can be declared by
naming a member function with the same name as the class. This constructor function will be called
automatically when a new instance of the class is created (when declaring a new object or allocating an
object of that class) and only then. We are going to implement CRectangle including a constructor:
Example: - // classes example
#include <iostream.h>
class CRectangle
{
int width, height;
public:
CRectangle (int a, int b) //constructor is created rect area: 12
{ rectb area: 30
width = a;
height = b;
}
int area (void)
{
return (width*height);
}
};
int main ( )
{
CRectangle rect (3,4);// object rect with initial value
CRectangle rectb (5,6);
cout << "rect area: " << rect.area() << endl;
cout << "rectb area: " << rectb.area() << endl;
}

The Destructor fulfills the opposite functionality of constructor. It is automatically called when an
object is released from the memory, either because its scope of existence has finished (for example, if it
was defined as a local object within a function and the function ends) or because it is an object
dynamically assigned and it is released using operator delete.
The destructor must have the same name as the class with a tilde ( ~) as prefix and it must return no
value.
The use of destructors is especially suitable when an object assigns dynamic memory during its life and
at the moment of being destroyed we want to release the memory that it has used.
Example on constructors and destructors
#include <iostream.h>
class CRectangle
{
int *width, *height;
public:
CRectangle (int a, int b)
{
width = new int;
height = new int;
*width = a;
*height = b;
}
5|Page
Debremarkos University Department of Information Technology

~CRectangle ( )
{
delete width;
delete height;
}
int area (void)
{
return (*width * *height);
}
};
int main ( )
{
CRectangle rect (3, 4), rectb (5, 6);
cout << "rect area: " << rect.area( ) << endl;
cout << "rectb area: " << rectb.area( ) << endl;
return 0;
}

 Overloading Constructors
Like any other function, a constructor can also be overloaded with several functions that have the same
name but different types or numbers of parameters. Remember that the compiler will execute the one
that matches at the moment at which a function with that name is called. In this case, at the moment at
which a class object is declared.
In fact, in the cases where we declare a class and we do not specify any constructor the compiler
automatically assumes two overloaded constructors ("empty constructor" and "copy constructor").
For example, for the class:
class CExample {
public:
int a,b,c;
void multiply (int n, int m)
{
a=n; b=m; c=a*b;
}
};
with no constructors, the compiler automatically assumes that it has the following constructor member
functions, empty constructor:
 Empty constructor
It is a constructor with no parameters defined as nop(empty block of instructions). It does nothing.
CExample::CExample ( ) { };
 Copy constructor
It is a constructor with only one parameter of its same type that assigns to every non-static class
member variable of the object a copy of the passed object.
CExample::CExample (const CExample & rv) {
a=rv.a; b=rv.b; c=rv.c;
}
It is important to realize that both default constructors: the empty constructor and the copy constructor
exist only if no other constructor is explicitly declared. In case that any constructor with any number of

6|Page
Debremarkos University Department of Information Technology

parameters is declared, none of these two default constructors will exist. So if you want them to be
there, you must define your own ones.
Of course, you can also overload the class constructor providing different constructors when you pass
parameters between parenthesis and when you do not (empty):
// overloading class constructors
#include <iostream.h>
class CRectangle {
int width, height;
public:
CRectangle ( );
CRectangle (int, int);
int area (void) {return (width*height);}};
CRectangle::CRectangle ( )
{
width = 5;
height = 5;
}
CRectangle::CRectangle (int a, int b)
{
width = a;
height = b;
}
int main ( )
{
CRectangle rect (3,4);
CRectangle rectb;
cout << "rect area: " << rect.area( ) << endl;
cout << "rectb area: " << rectb.area( ) << endl;
}
In this case rectb was declared without parameters, so it has been initialized with the constructor that
has no parameters, which declares both width and height with a value of 5.
CRectangle rectb; // right
CRectangle rectb( ); // wrong!

5.3. Data Abstraction in C++


Data abstraction refers to, providing only essential information to the outside world and hiding their
background details, i.e., to represent the needed information in program without presenting the details.
Data abstraction is a programming (and design) technique that relies on the separation of interface and
implementation.
Let's take one real life example of a TV, which you can turn on and off, change the channel, adjust the
volume, and add external components such as speakers, VCRs, and DVD players, but you do not know
its internal details, that is, you do not know how it receives signals over the air or through a cable, how
it translates them, and finally displays them on the screen.

7|Page
Debremarkos University Department of Information Technology

Thus, we can say a television clearly separates its internal implementation from its external interface
and you can play with its interfaces like the power button, channel changer, and volume control without
having zero knowledge of its internals.
Now, if we talk in terms of C++ programming, C++ classes provides great level of data abstraction.
They provide sufficient public methods to the outside world to play with the functionality of the object
and to manipulate object data, i.e., state without actually knowing how class has been implemented
internally.
For example, your program can make a call to the sort( ) function without knowing what algorithm the
function actually uses to sort the given values. In fact, the underlying implementation of the sorting
functionality could change between releases of the library, and as long as the interface stays the same,
your function call will still work.
In C++, we use classes to define our own abstract data types (ADT). You can use the cout object of
class ostream to stream data to standard output like this:
#include <iostream>
int main( ){
cout << "Hello C++" <<endl;
return 0; }
Here, you don't need to understand how cout displays the text on the user's screen. You need to only
know the public interface and the underlying implementation of cout is free to change.
 Access Labels Enforce Abstraction:
In C++, we use access labels to define the abstract interface to the class. A class may contain zero or
more access labels:
 Members defined with a public label are accessible to all parts of the program. The data-
abstraction view of a type is defined by its public members.
 Members defined with a private label are not accessible to code that uses the class. The private
sections hide the implementation from code that uses the type.
There are no restrictions on how often an access label may appear. Each access label specifies the
access level of the succeeding member definitions. The specified access level remains in effect until the
next access label is encountered or the closing right brace of the class body is seen.
 Benefits of Data Abstraction:
Data abstraction provides two important advantages:
 Class internals are protected from unintentional user-level errors, which might corrupt the state
of the object.
 The class implementation may evolve over time in response to changing requirements or bug
reports without requiring change in user-level code.
By defining data members only in the private section of the class, the class author is free to make
changes in the data. If the implementation changes, only the class code needs to be examined to see
what affect the change may have. If data are public, then any function that directly accesses the data
members of the old representation might be broken.

8|Page
Debremarkos University Department of Information Technology

 Data Abstraction Example:


Any C++ program where you implement a class with public and private members is an example of data
abstraction. Consider the following example:
#include <iostream.h>
class Adder{
public:
// constructor
Adder(int i = 0) {
total = i; }
// interface to outside world
void addNum(int number) {
total += number; }
// interface to outside world
int getTotal( ) {
return total; }
private:
// hidden data from outside world
int total;};
int main( ){
Adder a;
a.addNum(10);
a.addNum(20);
a.addNum(30);
cout << "Total= " << a.getTotal( ) <<endl;
return 0;}
When the above code is compiled and executed, it produces the following result:
Total = 60
Above class adds numbers together, and returns the sum. The public members’ addNum and getTotal
are the interfaces to the outside world and a user needs to know them to use the class. The private
member total is something that the user doesn't need to know about, but is needed for the class to
operate properly.
To make parts of a class public (i.e., accessible to other parts of your program), you must declare them
after the public keyword. All variables or functions defined after the public specifier are accessible by
all other functions in your program.

5.4. C++ Inheritance


Inheritance is the process by which objects of one class acquired the properties of objects of another
classes. It supports the concept of hierarchical classification. For example, the bird, ‘robin’ is a part of
class ‘flying bird’ which is again a part of the class ‘bird’. The principal behind this sort of division is
that each derived class shares common characteristics with the class from which it is derived.
In OOP, the concept of inheritance provides the idea of reusability. This means that we can add
additional features to an existing class without modifying it. This is possible by deriving a new class
from the existing one. The new class will have the combined feature of both classes. The real appeal
and power of the inheritance mechanism is that it allows the programmer to reuse a class i.e almost, but
not exactly, what he wants, and to tailor the class in such a way that it does not introduced any
undesirable side-effects into the rest of classes.
9|Page
Debremarkos University Department of Information Technology

When creating a class, instead of writing completely new data members and member functions, the
programmer can designate that the new class should inherit the members of an existing class. This
existing class is called the base class, and the new class is referred to as the derived class.
 Base & Derived Classes:
A class can be derived from more than one classes, which means it can inherit data and functions from
multiple base classes. To define a derived class, we use a class derivation list to specify the base
class/es. A class derivation list names one or more base classes and has the form:
class derived-class: access-specifier base-class
Where access-specifier is one of public, protected, or private, and base-class is the name of a previously
defined class. If the access-specifier is not used, then it is private by default.
Consider a base class Shape and its derived class Rectangle as follows
#include <iostream.h>
// Base class
class Shape
{
public:
void setWidth(int w){
width = w;}
void setHeight(int h){
height = h; }
protected:
int width;
int height;
};
class Rectangle: public Shape // Derived class
{
public:
int getArea( ){
return (width * height); }
};
int main(void){
Rectangle Rect;
Rect.setWidth(5);
Rect.setHeight(7);
// Print the area of the object.
cout << "Total area: " << Rect.getArea() << endl;
return 0;}
When the above code is compiled and executed, it produces the following result:
Total area: 35
 Access Control and Inheritance:
A derived class can access all the non-private members of its base class. Thus base-class members that
should not be accessible to the member functions of derived classes should be declared private in the
base class. We can summarize the different access types according to who can access them in the
following way:

10 | P a g e
Debremarkos University Department of Information Technology

 Type of Inheritance:
When deriving a class from a base class, the base class may be inherited through public, protected or
private inheritance. The type of inheritance is specified by the access-specifier as explained above. We
hardly use protected or private inheritance, but public inheritance is commonly used. While using
different type of inheritance, following rules are applied:
 Public Inheritance: When deriving a class from a public base class, public members of the base
class become public members of the derived class and protected members of the base class
become protected members of the derived class. A base class's private members are never
accessible directly from a derived class, but can be accessed through calls to the public and
protected members of the base class.
 Protected Inheritance: When deriving from a protected base class, public and protected members
of the base class become protected members of the derived class.
 Private Inheritance: When deriving from a private base class, public and protected members of the
base class become private members of the derived class.
 Multiple Inheritances:
A C++ class can inherit members from more than one class and here is the extended syntax:
class derived-class: access baseA, access baseB....
where access is one of public, protected, or private and would be given for every base class and they
will be separated by comma as shown above. Let us try the following example:
#include <iostream.h>
// Base class Shape
class Shape {
public:
void setWidth(int w){
width = w; }
void setHeight(int h){
height = h;}
protected:
int width;
int height;};
// Base class PaintCost
class PaintCost {
public:
int getCost(int area){
return area * 70; }};

// Derived class
class Rectangle: public Shape, public PaintCost{
public:
int getArea() {
return (width * height); }};
int main(void){
Rectangle Rect;
int area;
Rect.setWidth(5);
11 | P a g e
Debremarkos University Department of Information Technology

Rect.setHeight(7);
area = Rect.getArea( );
// Print the area of the object.
cout << "Total area: " << Rect.getArea() << endl;
// Print the total cost of painting
cout << "Total paint cost: $" << Rect.getCost(area) << endl;
return 0;}

5.5. Polymorphism
Polymorphism is another important OOP concept. Polymorphism, a Greek term, means the ability to
take more than one form. An operation may exhibit different behavior in different instances. The
behavior depends upon the types of data used in the operation. For example, consider the operation of
addition. For two numbers, the operation will generate a sum. If the operands are strings, then the
operation would produce a third string by concatenation. The process of making an operator to exhibit
different behaviors in different instances is known as operator overloading.

The following figure illustrates that a single function name can be used to handle different number and
different types of argument. This is something similar to a particular word having several different
meanings depending upon the context. Using a single function name to perform different type of task is
known as function overloading.

Polymorphism plays an important role in allowing objects having different internal structures to share
the same external interface. This means that a general class of operations may be accessed in the same
manner even though specific action associated with each operation may differ. Polymorphism is
extensively used in implementing inheritance.
C++ polymorphism means that a call to a member function will cause a different function to be
executed depending on the type of object that invokes the function.

5.6. C++ Overloading (Operator and Function)


C++ allows you to specify more than one definition for a function name or an operator in the same
scope, which is called function overloading and operator overloading respectively. An overloaded
declaration is a declaration that had been declared with the same name as a previously declared
declaration in the same scope, except that both declarations have different arguments and obviously
different definition (implementation).

12 | P a g e
Debremarkos University Department of Information Technology

When you call an overloaded function or operator, the compiler determines the most appropriate
definition to use by comparing the argument types you used to call the function or operator with the
parameter types specified in the definitions. The process of selecting the most appropriate overloaded
function or operator is called overload resolution.

 Function overloading in C++


You can have multiple definitions for the same function name in the same scope. The definition of the
function must differ from each other by the types and/or the number of arguments in the argument list.
You cannot overload function declarations that differ only by return type. The following is the example
where same function print( ) is being used to print different data types:
#include <iostream.h>
class printData {
public:
void print(int i) {
cout << "Printing int: " << i << endl;}
void print(double f) {
cout << "Printing float: " << f << endl;}
void print(char* c) {
cout << "Printing character: " << c << endl;}};
int main(void){
printData pd;
// Call print to print integer
pd.print(5);
// Call print to print float
pd.print(500.263);
// Call print to print character
pd.print("Hello C++");
return 0;}
When the above code is compiled and executed, it produces the following result:
Printing int: 5
Printing float: 500.263
Printing character: Hello C++
 Overriding
Defining a function in the derived class with same name as in the parent class is called overriding. In
C++, the base class member can be overridden by the derived class function with the same signature as
the base class function. Method overriding is used to provide different implementations of a function so
that a more specific behavior can be realized.

5.7. Relationships between classes


 Friend functions (friend keyword)
In the previous section we have seen that there were three levels of internal protection for the different
members of a class: public, protected and private. In the case of members protected and private, these
could not be accessed from outside the same class at which they are declared. Nevertheless, this rule
can be disobeyed with the use of the friend keyword in a class, so we can allow an external function to
gain access to the protected and private members of a class.

13 | P a g e
Debremarkos University Department of Information Technology

In order to allow an external function to have access to the private and protected members of a class we
have to declare the prototype of the external function that will gain access preceded by the keyword
friend within the class declaration that shares its members. In the following example we declare the
friend function duplicate:

Example for friend functions


#include <iostream.h>
class CRectangle {
int width, height;
public:
void set_values (int, int);
int area (void) {return (width * height);}
friend CRectangle duplicate (CRectangle);};
void CRectangle::set_values (int a, int b) {
width = a;
height = b;}
CRectangle duplicate (CRectangle rectparam){
CRectangle rectres;
rectres.width = rectparam.width*2;
rectres.height = rectparam.height*2;
return (rectres);}
int main ( ) {
CRectangle rect, rectb;
rect.set_values (2,3);
rectb = duplicate (rect);
cout << rectb.area( );}
From within the duplicate function, that is a friend of CRectangle, we have been able to access the
members width and height of different objects of type CRectangle. Notice that neither in the declaration
of duplicate( ) nor in its later use in main( ) have we considered duplicate as a member of class
CRectangle.

The friend functions can serve, for example, to conduct operations between two different classes.
Generally the use of friend functions is out of an object-oriented programming methodology, so
whenever possible it is better to use members of the same class to make the process. Such as in the
previous example, it would have been shorter to integrate duplicate ( ) within the class CRectangle.

14 | P a g e
Debremarkos University Department of Information Technology

 Friend classes (friend)


Just as we have the possibility to define a friend function, we can also define a class as friend of another
one, allowing that the second one access to the protected and private members of the first one.

Example for friend class


#include <iostream.h>
class CSquare
{
private:
int side;
public:
void set_side (int a)
{side=a;}
friend class CRectangle;
};
class CRectangle
{
int width, height;
public:
int area (void)
{
return (width * height);
}
void convert (CSquare a);
};
void CRectangle::convert (CSquare a) {
width = a.side;
height = a.side;}
int main ( ) {
CSquare sqr;
CRectangle rect;
sqr.set_side(4);
rect.convert(sqr);
cout << rect.area( );
return 0;}
In this example we have declared CRectangle as a friend of CSquare so that CRectangle can access the
protected and private members of CSquare, more concretely CSquare::side, that defines the square side
width.
You may also see something new in the first instruction of the program that is the empty prototype of
class CSquare. This is necessary because within the declaration of CRectangle we refer to CSquare(as a
parameter in convert()). The definition of CSquare is included later, so if we did not include a previous
definition for CSquare, the class would not be visible from within the definition of CRectangle.

15 | P a g e

You might also like