Object Oriented Programming Classes & Objects
Introduction
In the world, if we see around ourselves, we always find things sharing common property(ies), on the basis of which they can be grouped together and can be put into one set, like, vehicles, toys, furniture etc. Not only that the non living things, but the living things also share common trait(s) on the basis of which they have been classified into various kingdoms and further species. Here in this concept, the vehicle, the furniture, the toy, all form ‘a class’. Whereas, the type of vehicle - like car, scooter etc. - or the type of furniture - like bed, dinning table etc. - form a subclass. However, the car number 68XY or ‘U’ model bed are the examples of ‘objects’ or ‘instances’.
Whenever we talk about object oriented analysis and design, the concept of class is first and foremost. A class is not only a new way of defining and implementing the data types by users but it is also a mean to model the real world behavior. Classes are the actual modeling of the object-oriented concept.
The object can be visualized as A CONTAINER THAT CONTAINS BOTH DATA AND CODE TO MANIPULATE THE DATA. Objects and classes are interrelated to each other as A CLASS IS A COLLECTION OF SIMILAR OBJECTS. As we saw earlier that the class is a user defined data type, hence the entire set of data and code of an object can be made a user defined data type with the help of class.
Every object is directly related to a class. Objects are nothing but instances of class. A class can be defined as a collection of objects of similar type. Thus a class is generalization of objects having similar attributes and operations. A class consists of two parts, one is class data types and the other is class data functions. These are collectively called class members.
Within a class, the visibility level of class members is very important.. A class member can be one of the two types: PRIVATE or PUBLIC. As the name suggests, a private member can be seen only inside the class, whereas the public class member can be seen, accessed and mutated outside the class as well.
A class is an ABSTRACT DATA TYPE since it follows the concept of ABSTRACTION. Abstraction is the mechanism, which only shows the necessary information to the user, while hiding background details or implementation. Rotation of a fan by turning ‘on’ an electrical switch, without any additional effort or information requirement, is clearly an example of abstraction. Then, we come to an important concept of the object-oriented analysis, which is DATA HIDING AND ENCAPSULATION. Both of these terms are tightly interrelated and are very similar to each other. Data Hiding is a very broad term that means insulating the data such that is cannot be directly accessed by the program. Encapsulation is a specific method of this term in which we wrap up both the data and the function in a single unit (class).
Data Members
Before understanding the data members, let us first of all make a sample class of our own. This program will consist of a class and three objects of that class. Let us make a class called book. This class will have some properties such as cost of the book and the number of pages in the book. Therefore, we take variables called cost and pages that represent respectively cost of the book and number of pages in the book. C++ uses // for inline comments and /* ____ */ for multi-line comments.
The general form of a class declaration is :
class class_name{ private:
data/variable declarations;
function declarations;
public:
data/variable declarations;
function declarations;
};
- PRIVATE: The ‘private’ access specifier indicates that the members declared under it can be accessed only by the member functions of the class.
- PUBLIC: The public visibility label indicates that the members declared under it can be accessed from outside the class also (by the functions outside the class).
- PROTECTED: The protected label is used when a class wants to inherit the members from another class.
Following is a demonstration for a class declaration.
// book.cpp// demonstration of a small class illustrating the data members
#include //preprocessor directive
class book //declaration of the class
{
private: //visibility label
float cost; //variable declaration for the cost of book
int pages; //variable declaration for the number of pages of //the book
};
void main()
{
book b1,b2; //creating objects of class book
}
In this class book we have three important attributes called cost and pages. These are the variable data members of the class book as they can take different values for different objects. Now the cost will be of float type as it will be in rupees and paise. The pages of the book will be of type int (integer) as the pages are whole numbers. Thus the data members are the variables used to represent the attributes of the class. Two important decisions have to be taken while deciding the attributes (data members) of the class. The first is to decide attributes that will model the class. It also involves deciding meaningful names for the variable names that follow the semantics of the language. The second important decision is to decide upon the data type that each of the variables will take.
Member Functions: Definition and Pass Values (Arguments)
Member Functions are functions that are included within the class. These model the operations of the class.
There are two types of member functions
1. Accessor Functions
2. Mutator Functions
As the name suggests, the accessor functions access the data (for class variables). Thus, through accessor functions the value of the member variable is determined. The mutator function changes or mutate the data according to the argument passed.The accessor functions usually start with show prefix while the mutator functions are prefixed with set.
A more traditional format for these function definitions are:
void setdata(int d){
data=d;
}
void showdata()
{
cout<< “\nData is <
}
One important property of the mutator function is that it always contains some argument. While the accessor function may or may not contain any argument. Whenever we pass some message to the function by invoking it, we do so by passing arguments. The arguments are inside brackets alongside the name of function. For example, in above-mentioned case, d (int type) is the argument of function setdata().
To further clear this concept let us further define our earlier class book.In this example, we have two accessor and two mutator methods. The accessor methods are showcost() and showpages() and the mutator methods are setcost() and setpages() respectively.
// book.cpp// This class demonstrates a small class illustrating the data members as well as
//the member functions
#include //preprocessor directive
class book //declaration of the class
{
private: //visibility label
float cost; //variable declaration for the cost of book
int pages; //variable declaration for the number of pages of
//the book
public:
//Mutator methods
void setcost( float c)
{
cost=c;
}
void setpages( int p)
{
pages=p;
}
//Accessor methods
void showcost()
{
cout<< “\nThe cost of the book is:”<
}
void showpages()
{
cout<<”\n The number of pages in this book are:”<
}
}; //end of class declaration
void main()
{
book b1,b2;
b1.setcost(100.50); /* invoke mutator method ‘setcost’ for object b1*/
b1.setpages(223);
b2.setcost(200.25); /* invoke mutator method ‘setcost’ for object b2*/
b2.setpages(540);
b1.showcost(); /* invoke accessor method ‘showcost’ for b1*/
b1.showpages();
b2.showcost(); /* invoke accessor method ‘showcost’ for b2*/
b2.showpages();
} /* end of main */
To access the private features of the class, i.e. the class data members, we have to take the help of functions. When the function is called, the control is transferred to the first statement in the function definition. One by one all the statements within the function definition are executed until the ending brace is encountered. When the program control encounters ending brace, the control returns to the main program from where it was originally called. The function definition consists of declarator/header that is followed by the body of function. The function body is the actual definition of the function. It consists of the statements that make up the function, delimited by the ending braces. The declarator must agree with the semantics of the declaration. First of all, it must use the same name for the function, then it should have the same argument types in the same order along with having the same return type. One important thing must be noted that the function definition doesnot end with a semi colon as the class does. The arguments are passed through functions that in turn set or change the values of the class variables. In this example, we are using two objects b1 and b2. To access the functions of the class, the dot (.) operator is used. The format used is the name of object followed by “.”, followed by the name of function further followed by arguments inside the parentheses of function (if any). The arguments are the actual values passed to the function.
b2.setpages(540);
540 is the value of the pages passed to the function setpages(). This function setpages() belongs to object b2 and thus after this statement the object b2, or more specifically the book b2 has number of pages as 540. Another way of defining functions is to DEFINE THEM OUTSIDE THE CLASS. These definitions are muck like that of normal functions, with a function header and a function body. The difference is that such a member function must have an IDENTITY LABEL in its header. This label tells the compiler which class the function belongs to. The identity label comprises the name of the class and SCOPE RESOLUTION OPERATOR (::). As the name suggests, the scope resolution operator defines the scope (boundary) of a function (in terms of which class it belongs to). The syntax is :
return_type class_name :: function_name( argument ){
function body; }
For example in the statement
Consider the following example, demonstrating the use of scope resolution operator:
class integer{ private:
int i,j;
public:
void getdata(int x, int y); /*prototype declaration*/
void showdata(); /*prototype declaration*/
};
void integer :: getdata(int x, int y) // definition of the function outside class
{ i=x;
j=y;
}
void integer :: showdata() // definition of the function outside class
{ cout<<”\n i= “<
cout<<”\n j= “<
}
void main()
{
integer i1;
i1.getdata();
i1.showdata();
}
Data Hiding and Encapsulation (Private and Public Members)
A class can be defined as an entity that binds the data and its associated functions together. It allows the data to be hidden from the user, if necessary. When defining a class, we are creating a new abstract data type that can be treated like any other built-in-type.
Generally, a class specification has two parts:
1. Class declaration
2. Class function declaratio
The class declaration describes the type and scope of its members. Thus the class declaration is the definition of the class itself. It consists of the class attributes and the class functions. The class function declarations describe how the class functions are implemented. Thus, the class function declaration is the actual implementation of the class operations. 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 of the members are private and which of them are public. The keywords private and public are known as visibility labels as they characterize the level of visibility. In other words we can say that the visibility labels describe the level of transparency of the members inside or outside the class. The members that are declared as public can be accessed from anywhere, outside or inside the class. On the other hand, the private members can be accessed only from the inside of the class. Thus public and private members implement the data encapsulation of the Object Oriented Programming. There are two important terms viz. data members and member functions. The data members are the variables declared inside the class whereas the member functions are the functions. The public members can be accessed from anywhere including from outside the class. Only the member functions can access the private data members and private functions. Therefore, encapsulation can be defined as the binding together of data and functions into a single class type variable. By information hiding we mean that the internal implementation details of the data and functions (members of a class) are kept hidden from the outside world. Thus, whenever changes occur, the side effects are avoided. Through information hiding, data structures and the operations manipulating them are encapsulated into one entity- the class. This promotes the reusability of components of class or the class as such. Then, the interfaces between the encapsulated objects are also simplified through encapsulation. Any object sending the message across need not be concerned with the internal implementations details. Thus, messaging is facilitated and bugs are reduced.
Default Label
The default visibility label or access specifier is PRIVATE. The class definition of book can be re-written as:
class book{ float cost;
int pages;
public:
void setcost(float c);
void setpages(int p);
void showcost();
void showpages();
};
Thus, the members ‘cost’ and ‘pages’ are private in the class ‘book’.
Arrays Within a Class
Within a class’s definition, an array can be used as a member variable. For example, observe the following class definition:
#include#define SIZE 10
class myarray
{
int arr[SIZE];
private:
void input(void);
void output(void);
}; /*class definition ends*
Here arr[] is declared as a private member of the class array. This can be used in the member function just like any other variable.
Any sort of operation can be performed on the array members. For example, in the above class definition, the function input() can be used to set the values of the elements of the array. The member function output() can be used to show the set values of the array elements. Thus, any functionality can be provided to the arrays depending upon the need. The definitions of the functions declared above, is as follows:
void myarray :: input(){
int i;
for (i=0;i
cin >> arr[i];
}
void myarray :: output()
{
int j;
for (j=0; j
cout<<”\n “<
}
void main()
{
myarray a; /* create object ‘a’ of class myarray */
cout<<”\n ENTER 10 VALUES :”
a.input();
cout<<”\n VALUES ENTERED BY YOU ARE : “;
a.output();
}
The variables, i and j used as counter in functions input() and output() respectively are local variables with their scope bound to member functions.
Friend Functions
“FRIEND FUNCTIONS” or “FRIENDLY FUNCTIONS” are like ordinary functions but they have ACCESS TO PRIVATE DATA MEMBERS OF THE CLASS to which they are declared “friend”. ‘Friend Functions’ is one way through which C++ provides a mechanism to break the wall of encapsulation created around members of a class, by use of ‘private’ label. But, it should never be forgotten that friend function can access the private data members through objects of the class, using dot membership operator. The following are salient characteristics of a friend functions:
A friend function lies outside the scope of class to which it is a ‘friend’.
An object of the class to which it is a friend cannot call a friend function. This is because a friend function is like a normal function and is called like a normal function without the use of object and dot operator.It does not access the members directly. Instead, it does so through an object and dot membership operator.Declaration of friend function in private or public section does not make any difference to its meaning.
Consider an example of a friend function “display( )”, to print private data members of an object.
#includeclass sample
{
int value;
public :
void input(); /*member function prototype
*/
friend void display(sample); /*friend function
declaration */
}; /*class definition end */
void sample::input()
{
cout<<”\n Enter the value of sample. “;
cin>>value;
}
void display(sample s)
{ /*access private member through object of class */
cout<”<
}
void main()
{
sample s;
s.input();
display(s); /*invoke a friend function, like an ordinary function */
}
display is a friend function to class “sample” .It is declared inside the class by preceeding the function header with keyword “friend” .It is defined like any other normal function. It is invoked in main and passed an object of sample class, ‘s’. The function then displays the private member value, using the syntax “s.value”, Friend function find their use when two classes need to share a particular function. In such a case a common function is made friendly to both the classes.
Must to Remember
Member functions are allocated space (memory) only once when they are defined as a part of class specification, whereas data members are not allocated space while declaring the class. Data members are created, only when object of class is declared. Hence,” DIFFERENT OBJECTS OF SAME CLASS HAVE DIFFERENT COPIES OF DATA MEMBERS (ATTRIBUTES) BUT SHARE SAME SET/COPY OF MEMBER FUNCTIONS (BEHAVIOR)”.
Constructors and Destructors
One of the objectives of C++ is to create user-defined data types that behave like in-built data types. Thus, statements like:
integer i1= 10;
where i1 is an object of class integer, should be allowed just as it is allowed for in-built data type.
float x=7.95; /*allowed*/
The requirement of user-defined type, behaving as pre-defined or in-built type can be achieved by making use of constructor. A constructor is a member function which shares the name of the class and is used to initialize the object when it is created. A constructor is called automatically, as soon as an object is declared to a class. Constructors without any parameter are called DEFAULT CONSTRUCTORS whereas the one with parameters passed to it, is known as PARAMETERIZED CONSTRUCTOR. The following are salient characteristics of a constructor:
It should be declared in the public section. It is invoked automatically when an object is created. It does not have a return type, not even void. It cannot be inherited, though a derived class can call base class constructor. It can have default arguments (default arguments are those arguments whose default value is specified at the time of function declaration. If no value is passed to the function for that parameter at the time of call, default value is taken for that particular parameter). Constructor cannot be referred to by their addresses.
On the other hand, destructors are member functions which share the name of the class, preceded by the ~(tilde) operator and are used to destroy the objects when their scope (objects’ scope) is over. A destructor never takes argument or return value. It is invoked implicitly when the program is exit. Destructors are particularly essential to use when “new” operator has been used in the program for dynamic memory allocation. Destructors may use “delete” operator for cleaning up (de-allocating) the memory not required.
Consider the coding given below, which shows the use of default constructor, parameterized constructor and destructor in a class.
class integer{
int i,j;
public :
integer() /* default constructor */
{ i=0;
j=0;
}
integer(int x) /* parameterized constructor with one parameter */
{
i=x;
j=x;
}
integer (int x, int y) /* parameterized constructor with two parameters */
{
i=x;
j=y;
}
}; /* end of class */
void main()
{
integer i1; /* call to default constructor */
i1.display();
integer i2(10); /*call to parameterized constructor having one
parameter */
i2.display();
integer i3(10,30); /* call to parameterized constructor
having two parameters */
i3.display();
} /* destructors for i3, i2 and i1 are called automatically */
It is important to note that the class integer contains three constructors, having the same name but differing in their argument types, order or number. Such a use of constructors is known as CONSTRUCTOR OVERLOADING.
Constructor overloading helps in dynamic initialization of objects by providing various initialization formats during runtime. Further, the statements given below are semantically (according to their meaning) same:
integer i2(10); /* call to single-argument constructor */integer i2=10; /* call to single-argument constructor */
But this format of initialization is available for constructor having only one parameter. For constructor having more than one parameter, the arguments must be enclosed within parentheses, separated by comma.