Você está na página 1de 80

Module 1 INTRODUCTION 1.

1 Procedure Oriented Programming/Structured Programming The traditional programming languages like C, FORTRAN, Pascal, and Basic are Procedural Programming Languages. A procedural program is written as a list of instructions, telling the computer, step-by-step, what to do: Get two numbers, add them and display the sum. The problem is divided into a number of functions. The primary focus of programmer is on creating functions. While developing functions, very little attention is given to data that are being used by various functions. Procedural programming is fine for small projects. It does not model real world problems well. This is because functions are action oriented and does not really correspond to the elements of the problems.

Main Program

Function1

Function2

Function3

Function4

Function5

Fig: Typical structure of Procedural Oriented Program


Features of Structured Programming Language

Emphasis is on algorithm (step by step description of problem solving) to solve a problem. Each step of algorithm is converted into corresponding instruction or code in programming language. Large program is divided into a number of functions, with each function having a clearly defined purpose and a clearly defined interface to other functions in the program. The integration of these functions constitutes a whole program. Uses top-down approach in program design. In top-down programming, we conceive the program as a whole as a process to be decomposed. We decompose the problem into sub-problems with the following three characteristics: i. The sub-problem stands alone as a problem in its own right ii. The sub-problem appears to be solvable, though we may not have an immediate solution, and iii. If all of the sub-problems in the decomposition are solvable, then we know a composition that will put the solutions of the sub-problems together as a solution of the original In multi-function program, data items that are important and that are used by more than one functions, are placed as global so that they may be accessed by all the functions. Global data are more vulnerable to accidental changes. Data move openly around the system from function to function. Information is passed between functions using parameters or arguments.

1.2 Object-Oriented Programming Language In Object-Oriented Programming, a program is decomposed into a number of entities called objects. Data and the functions that operate on that data are combined into that object. OOP mainly focus on data rather than procedure. It considers data as critical element in the program development and does not allow it to flow freely around the system. It ties data more closely to the functions that operate on it and protects it from accidental modification from outside functions. .

Data

Data

Object B

Functions

Functions

Object A Functions Object C Data Organization of data and functions in OOP


Features of Object Oriented Programming Language Emphasis is on the data rather than procedure. It focuses on security of data from unauthorized modification in the program. A program is divided into a number of objects. Each object has its own data and functions. These functions are called member functions and data are known as member data. Data is hidden and can not be accessed by external functions. Follows bottom-up approach in program design. The methodology for constructing an object-oriented program is to discover the related objects first. Then, appropriate class is formed for similar objects. These different classes and their objects constitute a program. Object may communicate with each other through functions. New data and functions can be easily added whenever necessary. Once a class has been written, created and debugged, it can be used in a number of programs without modification i.e. a same code can be reused. It is similar to the way a library functions in a procedural language.

Basic Characteristics of Object-Oriented Languages Objects

They are basic runtime entities of an object oriented system. An object represents an individual, identifiable item, unit, or entity, either real or abstract, with a well-defined role in the problem domain. An object may be Tangible Things as a car, printer, ... Roles as employee, boss, ... Incidents as flight, overflow, ... Interactions as contract, sale, ... Specifications as colour, shape,

Elements of Computer- User environment as Windows, Menu etc In object-oriented programming, problem is analyzed in terms of objects. Programming object should be chosen such that they match closely with the real world objects. Objects take up space in memory. During program execution, objects interact by sending message to one another. Each object contains data and code to manipulate them. It can be defined as Object = Data + Methods or functions
Classes A class may be defined as a collection of similar objects. In other words, it is a general name for all similar objects. For example, mango, apple, banana all may be described under the common name fruits. Thus, fruits is class name for objects like mango, apple, and banana. In fact, a class is user defined data type and behaves like the built-in data types of programming languages. A class serves as a blue print or a plan or a template. It specifies what data and what functions will be included in objects of that class. Once a class has been defined, we can create any number of objects belonging to that class. If fruits has been defined as a class, then statements fruits mango; fruits apple; will create objects mango and apple belonging to the class fruits. This is similar to creating variables of built-in data types. Data abstraction and encapsulation Wrapping of data and functions into a single unit is known as data encapsulation. Data and functions of object are encapsulated using class. With data encapsulation, data is not accessible to the outside world, only the functions which are wrapped in the class can access them. These functions act as an interface between object's data and the program. This insulation of data is called data hiding. The act of representing essential features without including background details or explanations is called abstraction. Classes use the concept of abstraction. They are defined as the list of abstract attributes such as site, amount and functions to operate on these attributes. They encapsulate all the properties of the object to be created. As classes use the concept of abstraction, they are also called as abstract data types. Inheritance Inheritance is the process by which objects of one class acquires the properties of objects of another class. Inheritance allows us to create classes which are derived from other classes, so that they automatically include their "parent's" members, plus their own. Thus, a class can be divided into a number of sub classes. The derived classes are known as sub classes (or child classes) and original classes are called base classes or parent classes. For example, a class of animals can be divided into mammals, amphibians, insects, birds and so on. The class of vehicles can be divided into cars, trucks, buses and motor cycles. Each sub class shares common characteristics with the class from which it is derived. Cars, trucks, buses and motorcycles all have wheel and a motor; these are the defining characteristics of vehicles. In addition to these shared characteristics, each sub class also has its own characteristics: buses have seats for many people while trucks have space for heavy loads. The concept of inheritance provides the idea of reusability, means additional features can be added to an existing class without modifying it. In above example, the class buses can be inherited from base class vehicles. Then, all features of vehicles class are also of class buses. Thus, we do not need to mention common properties to class buses. The only special features of buses are included in class buses. The common properties are shared from class vehicles. Thus, Features of class buses= special features of class buses+ common features of class vehicles Reusability Object-oriented programming uses concept of reusability. Reusability implies the reuse of existing code in another program without modification to it. The concept of inheritance provides an idea of reusability in OOP. Once a class has been written, created and debugged, it can be used in another program. A programmer can use an existing class and without modifying it, add additional features and capabilities to it. This is done by deriving a new class from existing one. The new class will inherit the capabilities of the old one but is free to add new features of its own. Creating new data types Object-oriented programming gives the programmer a convenient way to construct new data type. Creating a class in object oriented programming can be considered as creating new data types. As we can define different variables of built-in data types like int, float, char, we can also create various objects of classes in similar manner. For example, if man is class name defined in the program, then man ram; will create an object ram of type man. Here man is a user defined data type. A class name specifies what data and what functions will be included in objects of that class. Polymorphism and overloading: The property of object-oriented programming polymorphism is ability to take more than one form in different instances. For example, same function name can be used for different purposes. Similarly, same operator can be used for different operations. Overloading (both function overloading and operator overloading) is a kind of polymorphism. If an operator exhibits different behaviors in different instances, then it is known as operator overloading. The type of behavior depends upon the type of the data used in the operation. Similarly, if a same function name is used to perform different types of tasks, then it is known as function overloading. The task to be performed by the function is determined by number of arguments and type of arguments.

Applications and Benefits of using OOP Applications of using OOP: Main application areas of OOP are User interface design such as windows, menu , Real Time Systems Simulation and Modeling Object oriented databases AI and Expert System Neural Networks and parallel programming Decision support and office automation system etc Benefits of OOP The main advantages are It is easy to model a real system as real objects are represented by programming objects in OOP. The objects are processed by their member data and functions. It is easy to analyze the user requirements.

With the help of inheritance, we can reuse the existing class to derive a new class such that redundant code is eliminated and the use of existing class is extended. This saves time and cost of program. In OOP, data can be made private to a class such that only member functions of the class can access the data. This principle of data hiding helps the programmer to build a secure program that can not be invaded by code in other part of the program. With the help of polymorphism, the same function or same operator can be used for different purposes. This helps to manage software complexity easily. Large problems can be reduced to smaller and more manageable problems. It is easy to partition the work in a project based on objects. It is possible to have multiple instances of an object to co-exist without any interference i.e. each object has its own separate member data and function.

1.3 History of Object Oriented Programming SIMULA was the first object language. As its name suggests it was used to create simulations. Alan Kay, who was at the University of Utah at the time, liked what he saw in the SIMULA language. He had a vision of a personal computer that would provide graphicsoriented applications and he felt that a language like SIMULA would provide a good way for non-specialists to create these applications. He sold his vision to Xerox Parc and in the early 1970s, a team headed by Alan Kay at Xerox Parc created the first personal computer called the Dynabook. Smalltalk was the object-oriented language developed for programming the Dynabook. It was a simulation and graphics-oriented programming language. Smalltalk exists to this day although it is not widely used commercially. The idea of object-oriented programming gained momentum in the 1970s and in the early 1980s Bjorn Stroustrup integrated objectoriented programming into the C language. The resulting language was called C++ and it became the first object-oriented language to be widely used commercially. In the early 1990s a group at Sun led by James Gosling developed a simpler version of C++ called Java that was meant to be a programming language for video-on-demand applications. This project was going nowhere until the group re-oriented its focus and marketed Java as a language for programming Internet applications. The language has gained widespread popularity as the Internet has boomed, although its market penetration has been limited by its inefficiency.

Module 2 Introduction to C++ 2.1 Data types in C++ The kind of data a variable may hold in a programming language is called it's data type. There are seven basic types built into C++. Of these basic types, one represents characters, three represent whole numbers (integers), and three represent real (floating-point) numbers. Table below summarizes the C++ basic data types. Type Name Used to Store char short int long float double long double

Examples of Values Stored Characters Small whole numbers Normal-sized whole numbers (same as short or same as long) Large whole numbers Small real numbers Large real numbers Extra-large real numbers a, B, $, 3, ? 7, 30,000, -222

1,000,000,000, -123,456,789 3.7, 199.99, -16.2, 0.000125 7,553.393.95,47, -0.048512934

9,123,456,789,012,345.666

C++ data types are similar to C. 2.2 Keywords/reserved words The syntax rules (or grammar) of C++ define certain symbols to have a unique meaning within a C++ program. These symbols, the reserved words, must not be used for any other purposes. The reserved words already used are int and void. All reserved words are in lower-case letters. The table below lists the reserved words of C++. and bitor char default else false if namespace or register sizeof template typedef Using While and_eq bool class delete enum float inline new or_eq reinterpret_cast static this typeid virtual xor asm break const do explicit for int not private return static_cast throw typename void xor_eq auto case const_cast double export friend long not_eq protected short struct true union volatile bitand catch continue dynamic_cast extern goto mutable operator public signed switch try unsigned wchar_t

Some of these reserved words may not be treated as reserved by older compilers. However you would do well to avoid their use. Other compilers may add their own reserved words. Typical are those used by Borland compilers for the PC, which add near, far, huge, cdecl, and pascal. Notice that main is not a reserved word. However, this is a fairly technical distinction, and for practical purposes you are advised to treat main, cin, and cout as if they were reserved as well.

2.3 Input and Output operators: cin/cout Output to the Screen The name cout, pronounced C out, represents a C++ object that is associated with the screen display. The << operator, called the insertion or put to operator, causes whatever is on its right to be sent to whatever is on its left. The cout object and the << operator are part of the C++ standard stream library, so you dont need to define them yourself or even worry too much about how they work. (You will need to insert a header file into your program to declare them) Heres a statement that causes a line of text to be displayed on the screen: cout << This text will appear on the screen.; The text This text will appear on the screen. is called a string constant. A string constant is surrounded by double quotes (unlike a character constant, which is surrounded by single quotes). The entire statement, as with all C++ statements, is terminated with a semicolon. You can output numerical constants the same way. The statement cout << 27; causes a 27 to appear on the screen, whereas cout << 123.45; displays 123.45. You can display the values of variables as well as numbers. For example, this code displays 2.7: float fvar1 = 2.7; cout << fvar1; More than one value can be displayed with a single cout statement, using multiple put to operators: float height = 2.7; cout << It is << height << meters high.; This would produce the output It is 2.7 meters high. It is 2.7 meters high. You can also reformat such a statement so that the put to operators line up vertically, thus making the statement easier to read: cout << It is << height << meters high.; Or you could use three separate cout statements to produce the same output. Input from the Keyboard Heres how to input a number, entered by the user from the keyboard, and store it in a variable intvar: int intvar; cin >> intvar; The cin object (for C in) represents the keyboard, and the extraction or get from operator (>>) takes whatever is on the left and puts it in the variable on the right. When this statement is executed, the program waits for the user to type a number and press Usually, of course, you want to prompt the user before waiting for input: int age; cout << Enter your age: ; cin >> age; This produces the following interaction: Enter your age: 34 where the user enters the 34. You can use the get from operator multiple times in the same statement: int age; float height; cout << Enter your age and height:; cin >> age >> height; Here the user presses , , or after each value before entering the next one. However, its usually better to prompt the user for only one value at a time, to avoid any possibility of confusion. 2.4 Typecasting (Standard Conversion and Promotions) When there are two operands of different types in an expression, the lower-type variable is converted to the type of the higher-type variable. For example, if one operand is of type int and other is of float, both are converted into float type. Thus, if data types are mixed in an expression, C++ performs the conversions automatically. This process is called implicit or automatic conversion. An example: void main() { int a=10; float b=40.5, result; result=a+b; cout<<"The sum is "<<result; } Output: The sum is 50.5. .

In this case, variable a is of type int while b is of type float. While solving the expression a+b, the temporary variable of type float is created to store value of a and then two float values are added. The result is of type float and stored in variable result. Here, data type int is promoted to float. Thus, it is also known as standard data type promotion. Other implicit conversions are int and float -> float int and long -> long int and double -> double long and float -> float float and double -> double But, sometime programmer needs to convert a value from one type to another explicitly in a situation where the compiler will not do it automatically. This type of conversion is called explicit conversion or type casting. An example: void main() { int a=4000; long result; result=a*100; cout<<"The product is "<<result; } Output: The product is 6784 // Error!!!!! The corrected version is: void main() { int a=4000; long result; result=long(a)*100; //type casting cout<<"The product is "<<result; } Output: The result is 400000 // correct Here, while solving the expression long(a)*100 in above program, integer type variable a is converted into long type. For this, a temporary variable of type long is created to store value of a and this long value is multiplied by 100 and result is also of type long. The long result is stored in variable result. Without casting, the result would not have been correct. This is because multiplication of two integers (i.e. a and 100) results integer value (i.e. 400000). But this integer value is beyond the range of integer. Thus, garbage value is stored in result variable.

2.5 Manipulators An object called a manipulator can be inserted into an output stream, just like a data item. Manipulators are the most common way to control output formatting. The following output manipulators control the format of the output stream. Include <iomanip.h> if you use any manipulators that have parameters. The Range column tells how long the manipulator will take effect: now inserts something at that point, next affects only the next data element and all affects all subsequent data elements for the output stream. Manipulator General output endl now Causes the cursor to move to the start of the next line, just as '\n does. (Also, endl flushes any output that may be waiting in the output buffer to the display.) eg. cout << endl; Sets minimum field width on output. This sets the minimum size of the field - a larger number will use more columns. Applies only to the next element inserted in the output. Use left and right to justify the data appropriately in the field. Output is right justified by default. Equivalent to cout.width(n); To print a column of right justified numbers in a seven column field: cout << setw(7) << n << endl; Same as setw(n). Left justifies output in field width. Only useful after setw(n). Right justifies output in field width. Since this is the default, it is only used to override the effects of left. Only useful after setw(n). Range Description

setw(n)

next

width(n) left right

next next next

setfill(ch)

all

Only useful after setw. If a value does not entirely fill a field, the character ch will be used to fill in the other characters. Default value is blank. Same effects as cout.fill(ch) For example, to print a number in a 4 character field with leading zeros (eg, 0007): cout << setw(4) << setfill('0') << n << endl;

Floating point output setprecision(n) all Sets the number of digits printed to the right of the decimal point. This applies to all subsequent floating point numbers written to that output stream. However, this won't make floating-point "integers" print with a decimal point. It's necessary to use fixed for that effect. Equivalent to cout.precision(n); Used fixed point notation for floating-point numbers. Opposite of scientific. If no precision has already been specified, it will set the precision to 6. Formats floating-point numbers in scientific notation. Opposite of fixed.

fixed scientific bool output boolalpha noboolalpha Input

all all

all

Uses alphabetic representation (true and false) for bool values. Turned off with noboolalpha.

skipws noskipws

all

For most input values (eg, integers and floating-point numbers), skipping initial whitespace (eg, blanks) is very useful. However, when reading characters, it is often desired to read the whitespace characters as well as the non-spacing characters. The these I/O manipulators can be used to turn whitespace skipping off and on. Eg, cin >> noskipws; turns whitespace skipping off for all subseqent cin input. Reads and ignores whitespace at the current position.

ws

now

Example #include <iostream> #include <iomanip> using namespace std; main() { const float tenth = 0.1; const float one = 1.0; const float big = 1234567890.0; cout<< "A. " << tenth << ", " << one << ", " << big << endl; cout<< "B. "<< fixed << tenth << ", " << one << ", " << big << endl; cout<< "C." << scientific<< tenth << ", " << one << ", " << big << endl; cout<<"D. "<<fixed<<setprecision(3)<< tenth<<", "<<one<<", "<<big<< endl; cout << "E. " << setprecision(20) << tenth << endl; cout << "F. " << setw(8) << setfill('*') << 34 << 45 << endl; cout << "G. " << setw(8) << 34 << setw(8) << 45 << endl; } produces this output: A. 0.1, 1, 1.23457e+009 B. 0.100000, 1.000000, 1234567936.000000 C. 1.000000e-001, 1.000000e+000, 1.234568e+009 D. 0.100, 1.000, 1234567936.000 E. 0.1000000014901161 F. ******3445 G. ******34******45 Lines F and G show the scope of setw() and setfill(). const This is C++ qualifier used for creating symbolic constant. Its syntax is const data_type variable_name= value; e.g. const int size=10; It specifies that the value of a variable (here, size) will not change throughout the program. Any attempt to alter the value of a variable defined with this qualifier will give error message by compiler. It is used for variables which do not change throughout the program like PI while calculating area of circle. In C++, the variable defined with this qualifier const should be initialized. Enumeration

The dictionary meaning of enumeration is counting, go through a list of articles naming them one by one. The process enumeration provides user defined data type, called enumerated data type which provides a way for attaching names to numbers. The syntax is enum tag_name {name1, name2, name3, .}; e.g. enum flag{false, true}; enum colour{red, blue, green, white}; Here, colour is enumerated data type whose permissible values are red, blue, green and white. Here, possible values red, blue, green and white are also called enumerators. These enumerators are attached with numbers 0,1,2 and 3 (i.e. o for red, 1 for blue and so on). Variables can be defined using this enumerated data type. These variables store only those values defined while defining enumerated data type. e.g. colour foreground; foreground=red // ok foreground=yellow; // not ok as yellow is not possible value for data type colour By default, the enumerators are assigned integers values starting with o for the first enumerator, 1 for second and so on. These can be explicitly assigned by the programmer as following. enum colour{red=7,blue, green, white}; // here, blue=8, green=9 and white=10 Characteristics: Although the enumerated data types are treated internally as integers, C++ does not permit an int value to be automatically converted to an enum value. E.g. colour foreground=2; // error colour foreground= (colour)2 // ok An enumerated value i.e. enumerator can be used in place of an int value. E.g. int num= red; // ok The enumeration provides an alternative means for creating symbolic constants. The enumerators value can be changed in the program. The anonymous enums (without enum_tag_name) can be created in C++. e.g. enum {red,blue,green,white}; An example: #include<iostream.h> #include<conio.h> void main() { clrscr(); enum days{sun,mon,tue,wed,thu,fri,sat}; days day1,day2; int mid_day; day1=sun; day2=sat; mid_day=wed; cout<<"day1= <<day1<<endl<<"day2="<<day2<<endl<<"Middle="<<mid_day; getch(); } Output: day1=0 day2=6 Middle=3 An another example which asks a number and test it for even or odd. #include<iostream.h> #include<conio.h> void main() { clrscr(); int num; enum flag{false, true}; flag even; cout<<"Enter a number to check even or odd"<<endl; cin>>num; if(num%2==0) even=true; else even =false; if(even) cout<<"The number is even"; else cout <<"The number is odd";

getch(); } Comments Comments in programming languages are those statements which are not needed to compile by the compiler. C++ supports both single line and multiple line comments. Single line comment is also known as double slash comment (i.e. //). It this comment is to be used for multiple line, we should use // for each line separately. e.g. //This is single line // comment used for multiple line Again, it supports C style comment (i.e. /* */). This type of comment is generally used for multiple lines. The lines between /* and */ are not compiled.

10

Module 3 FUNCTIONS What is a function? A function is a single comprehensive unit containing blocks of statements that performs a specific task. The task is repeated each time the function is called. So this avoids the need of rewriting the same code again and again. Every program must contain one function named main() from where the program begins its execution. When a function is called, the program execution is shifted to the first statement in the called function. After the function returns to the calling function, values can be returned and that value can be used as an operand in an expression. Why do we use function? To avoid rewriting the same code again and again

Separating the code into modular functions also makes the program easier to design, understand and debug Its not a good practice to write an entire program into one single function. Instead, breaking a program into smaller units and writing functions for each of these isolated subdivisions is the best way forward.
Defining a function A function definition has name, a parenthesis pair containing one or more parameters and a body. For each parameter, there should be a corresponding declaration that occurs before the body. The general format of the function definition is given as follows return_type function_name(datatype argument1,datatype argument2,.) { statement1; ; ; return ; } Declaring the type of the function The function may return varying type of value to the calling portion of the program. Any of the datatype such as int, float, char etc. can be in the function declaration. If a function is not supposed to return value, it can be declared as type void. Example of i) void myfunction ( float a,char b, int c) { ; ; } Example of ii) void myfunction ( void) { ; ; } Example of iii) float myfunction ( float a,char b, int c) { ; ; } Example of iv) int myfunction ( void ) { ; ; } Function Definition A function definition is a unit of a function itself with the type of value it returns and its parameters declared and the statements specified in it that are executed when the function is called. Actual arguments and Formal arguments Any variable declared in the body of a function is said to be local to that function. If the variables are not declared either as arguments or inside the function body, then they are considered global to the function and must be defined externally. Arguments defined inside the function are called formal arguments where as the arguments that have been declared at the calling function and whose values are passed to a function are known as actual arguments.

11

#include <iostream.h> void line(void); //function prototype or function declaration void line(void) //function definition { int j; for(j=1;j<=42;j++) cout<<"*; } void main(void) { clrscr(); cout<<"Welcome to the world of C programming "<<endl; line(); //function call } return statement The return() statement has two purposes. First, executing it immediately transfers control from the function back to the calling program. And second, whatever is inside the parentheses following return is returned as a value to the calling program. The return statement may or may not include an expression. If return contains no parameters then this return is used to transfer the control (used only with void) and if the return statement has got an argument then the argument is returned as a value to the calling portion of the program. There is no restriction on the number of return statements that may be present in a function. Also the return statement need not always be present at the end of the called function. Note: Using a return statement, only one value can be returned by a function at any given time Syntax: return ; return (expression); Example: A program to return value from a function. #include<iostream.h> #include<conio.h> float max_value(float,float); //function prototype or function declaration void main(void) { float x,y,max; cout<<"Enter the two numbers"; cin>>x>>y; max=max_value(x,y); cout<<Maximum value is:<<max; getch(); } float max_value(float a,float b) { if(a>b) return a; else return b; } User Defined Functions There are basically two types of functions - library functions and user-defined functions. Library functions are predefined in the header files and are not required to be written by the user at the time of writing of the program. Example of some library functions are getch(), getche(); User defined functions may be classified in the following three ways based on formal arguments passed and the usage of the return statement. a) A function is invoked without passing any formal arguments from the calling portion of a program and doesnt return any value back to the calling function. #include<iostream.h>

12

#include<conio.h> void main() { void display(void); //function declaration or function prototype display(); getch(); } void display(void) //Function definition { int x,y,sum; cout<<"Enter the value of x and y:"; cin>>x>>y; sum=x+y; cout<<"Sum="<<sum; } b) A function is invoked with formal arguments from the calling portion of a program but the function doesnt return any value back to the program. #include<iostream.h> #include<conio.h> void square(int); void main() { int max; cout<<"Enter the value :"; cin>>max; for(int i=1;i<=max;++i) square(i); getch(); } void square(int n) { int value; value=n*n; cout<<"Square of i is <<endl<<value; } c) Function is invoked without formal arguments from the calling portion of a program which returns a value back to the calling environment. #include<iostream.h> #include<conio.h> float area() { float r,result; cout<<"enter the radius:"; cin>>r; result=3.14*r*r; return result; } void main() { float a; a=area(); cout<<"area="<<a;

13

getch(); } Here function is defined before the actual calling of the function so it does not require function prototype. d) Function is invoked with formal arguments from the calling portion of a program which returns a value back to the calling environment. //Program to calculate factorial using function #include<iostream.h> #include<conio.h> int fact(int); void main(void) { int x,n; cout<<enter the number"; cin>>n x=fact(n); cout<<"The factorial is "<<x; getch(); }

int fact(int n) { int i,value=1; if(n==1) { return value; } else { for(i=1;i<=n;i++) { value=value*i; } return value; } //else ends here } //function fact ends here //Program to add two digits using function #include<iostream.h> #include<conio.h> float add(float,float); void main() { float x,y,sum; cout<<"Please enter value for x and y:\n"; cin>>x>>y; sum=add(x,y); cout<<"The Sum is:<<sum; getch() } float add(float c, float d) { float result;

14

} Rules that must be remembered while defining function A function prototype declaration must appear before calling the function. In a function prototype the type of the function and the type of each formal argument must be specified. The variable names used for formal arguments in a function prototypes are arbitrary; they may even be blanks. Each function prototype must be terminated by a semicolon. A function name may be any valid identifier. The type of the function specifies the type of the quantity which will be returned to the calling program.

result=c+d; return result;

The formal arguments used in defining a function may be scalars or arrays. Each formal arguments type must be specified. For example int add(float a,b,c) is invalid and should be in the form int add(float a,float b,float c) Within a function definition other variables may be declared and used. Such variables are local to the function and are not known outside the body of the function. Within a function definition one cannot define another function.

Rules that must be remembered while calling a function The actual arguments in the calling function must agree in number, order and type with the formal arguments in the function declaration. Copies of the values of actual arguments are sent to the formal arguments and the function is computed. Thus the actual arguments remain unchanged.

If the formal arguments are array names then the corresponding actual arguments in the calling function must also be array names of the same type. A return statement in the body of the function returns a value to the calling function. The type of expression used in return statement must match the type of the function declared. There may be functions without return statement. In such a case the function must be declared as void. A function can return only one value at one time.

The things discussed above are similar to C. Features added to C++ are: Default arguments Constant arguments Inline Function Function Overloading 3.1 Passing Default Arguments C++ allows a function to assign a parameter the default value in case no argument for that parameter is specified in the function call. Default values are specified when the function is declared. The compiler looks at the prototype to see how many arguments a function uses and alerts the program for a possible default value Default value is specified in a manner syntactically similar to a variable initialization. For example: float amount(float principle, int period, float rate=0.15) Here, default value of rate is 0.15 unless specified explicitly by the programmer. Objectives of using default arguments

These are useful when some variable always has a constant value or has the same value. For example: bank interest may remain the same for all customers for a particular period of deposit. Programmer can use only those arguments that are meaningful to a particular situation. Using default arguments means that the existing function call can continue to use the old number of arguments, while new function calls can use more.

Things to be remembered in assigning default value to the arguments Only the trailing arguments can have default values We must add default from right to left We cant provide default value to a particular argument in the middle of argument list. int mul(int i, int j, int k=0) //legal int mul(int i=0, int j, int k) //illegal int mul(int i=0, int j, int k=5) //illegal int mul(int i=2, int j=5, int k=6) //legal

Example 1 #include<iostream.h> #include<conio.h>

void pattern (char m, int n=2) { for(int i=0;i<n;i++)

15

cout<<m; cout<<endl; } void main() { pattern('*'); pattern('#',4); pattern('@',5); getch(); } Here in first function call, there is only one character argument * and second argument is not specified. So the function will take default value for unspecified parameter and will display the output as: * * Here in second function call, the first argument is character argument # and second argument is integer 4. So the function will take supplied value and will display the output as: # # # # Example 2 #include<iostream.h> #include<conio.h> int add(int p,int q=5); void printline(char ch='*',int len=40); main() {float amount; printline(); //use default for both argument amount=add(6); //put default for second argument cout<<"\n Final value="<<amount<<"\n\n"; printline('='); //use default for second argument getch(); } int add(int p, int q) { int sum; sum=p+q; return sum; } void printline(char ch, int len) { for(int i=1;i<=len;i++) cout<<ch; cout<<endl; }

Note: In first example function is defined before main, so there is no function prototype and default value is supplied in the function definition. But, in example 2 the function is defined after main and default value is supplied in the function prototype.
Problem Write a program to calculate the simple interest using default value of r =1.5%, r =12% per annum. I=PTR/100 Constant Arguments A C++ function may have constant argument(s). These argument(s) is/are treated as constant(s). These values can not be modified by the function. For making the argument(s) constant to a function, we should use the keyword const as given below in the function prototype: void max(const float x, const float y, const float z); Here, the qualifier const informs the compiler that the argument(s) having const should not be modified by the function max( ). 3.2 Inline functions When a same task is to done for many times, a function is used to save memory space. But, the use of function not only saves memory space but also adds extra overheads. One function call has to pass many steps like jumping to the function, saving registers, pushing arguments into the stack and returning to the calling function. A lot of time is taken by these instructions. When a function is small, a substantial percentage of execution time may be spent in such overheads. In case of small functions, the benefit obtained by saving

16

memory is less important or meaningful in comparison to extra overheads during function call. In this situation, one may even say the use of function is disadvantageous. They may say that instead of using function, using duplication of code to perform same task repeatedly is more advantageous. But duplication of code makes program unorganized and difficult to read. This problem is eliminated by inline function in C++. Inline functions are those functions that are expanded in line when they are invoked with the corresponding function code. That is, the compiler replaces the function call with the corresponding function code. All inline functions must be defined before they are called. A function is made inline by adding prefix inline to the function definition. The syntax is inline return_type function_name(argument_list) { } Example #include<iostream.h> #include<conio.h> inline float interst(float p, float t, float r) { return ((p*t*r)/100); } void main() { float result; result=interst(12000,2,10); cout<<"The interest is "<<result; } In this example, the function interst is defined as inline. Defining inline function is meaningful only for small functions. For large functions, the function call overhead becomes small compared to the execution of the function and the benefits of the inline functions may be lost. In such cases, the use of normal functions will be more meaningful. Usually, functions are made inline when they are small enough to be defined in one or more lines. The inline keyword merely sends a request, not a command, to the compiler. Thus, compiler may ignore this request if the function definition is too long or too complicated and compile the function as a normal function. Although, inline expansion makes a program run faster because the overhead of a function call and return is eliminated, but it makes the program take up more memory because the statements that define the inline function are reproduced at each point where the function is called. So, a trade off becomes necessary. When inline function may not work? For large functions For functions containing static variables For recursive functions For function containing a loop, a switch or a goto. In Short, Inline functions Save memory space, which becomes appreciable when a function is likely to be called many times It reduces the function call overhead, reduce extra time for calling function Program executes more efficiently Program becomes more readable Are better than a macro Notes: To make a function inline, all we need to do is to add prefix inline which is keyword in the function definition. Any function defined inside a class definition automatically become inline. Problems

1.
2. 3.

When will you make a function inline? Why? Describe with an example. What are the limitations of inline functions? Write a program using inline function to calculate the square of a number. Write a program using inline function to calculate the multiplication, division of two users input number.

3.3 Function Overloading Overloading refers to the use of the same thing for different purposes. This means that we can use the same function name to create functions that perform a variety of different tasks. This is known as function polymorphism in object oriented programming. An overloaded function appears to perform different activities depending on the kind of data sent to it. Using the concept of function overloading, we can design a family of functions with one function name but different argument list (may be different number of arguments or different type of arguments). The function would perform different operations depending on the argument list in the function call. The correct function is determined by either the number of arguments or the type of arguments. Examples: a) Different number of arguments #include<iostream.h> #include<conio.h>

17

int add(int, int); int add(int,int,int); void main() { int r1,r2; clrscr(); r1=add(10,30); // function add() is called which has only two arguments r2=add(20,30,40); //function add() is called which has three arguments cout<<"Result1="<<r1<<endl<<"Result2="<<r2; getch(); } int add(int a,int b) { return(a+b); } int add(int a, int b, int c) { return(a+b+c); } In this example, there are two user-defined functions named add() but they have been used for different purposes. One has been used to add two integer numbers and other has been used to add three integers. Appropriate function is called according to the number of arguments passed while invoking the function. In first call (i.e. add(10,30)), only two arguments have been passed. Thus first prototype (i.e. int add(int, int)) is used which adds two numbers. In second function call, three numbers have been passed. This one uses the second function. b) Different Kind of arguments: #include<iostream.h> #include<conio.h> int absolute(int x); long absolute(long y); void main() { int num,r1; long lnum,r2; clrscr(); cout<<"Enter an integer -ve or +ve"<<endl; cin>>num; r1=absolute(num); cout<<"Enter a long number -ve or +ve"<<endl; cin>>lnum; r2=absolute(lnum); cout<<endl<<"Absolute Value for int="<<r1<<endl<<"Absolute Value for long="<<r2; getch(); } int absolute(int a) { cout<<"I am from function 1"<<endl; return(a>0?a:a*-1); } long absolute(long a) { cout<<endl<<"I am from function 2"<<endl; return(a>0?a:a*-1); } Output: Enter an integer -ve or +ve -34 I am from function 1 Enter a long number -ve or +ve -120000 I am from function 2 Absolute Value for int=34 Absolute Value for long=120000 In this example, same function absolute() is used to calculate absolute value of both integer and long integer. Appropriate function is called according to the type of arguments passed to it. If integer is passed as an actual argument, then first function absolute is used which calculates absolute value of integer. Similarly, if long number is passed, the second absolute function is called which calculates absolute value of long integer. This is illustrated as output. Problems 1. Write a program to calculate the area of 3 objects namely cube, cylinder and rectangle using the concept of function overloading. 2. Use three different functions repeatchar( ), repeatchar(char ch) and repeatchar(char ch, int n) to perform the following tasks:

18

If argument is not supplied, it should print 20 asterisks. If only character argument is supplied, it should print that character 20 times. If both character and number are supplied as arguments, it should print that argument character that number of times as specified by the integer argument.

19

Module 4 Classes and Object Introduction Defining a class means creating user defined data type and it behaves like the built-in data types of programming languages. A class serves as a blue print or a plan or a template for an object. It specifies what data and what functions will be included in objects of that class. Once a class has been defined, we can create any number of objects belonging to that class. An object is an instance of a class. A class binds the data and its associated functions together. It allows the data to be hidden, if necessary, from external use. Declaration of Class Class declaration describes the type and scope of its members. Syntax for class declaration is like class class_name { private: variable declaration; function declaration; public: variable declaration; function declaration; }; an example: class box { private: float len, br, height; public: void get_data(); float volume(); }; Here, class is c++ keyword; class_name is name of class defined by user. The body of class enclosed within braces and terminated by a semicolon. The class body contains the declaration of variables and functions. These variables and functions are known as class members (member variables and member functions). Again, keyword private and public within class body specifies the visibility mode of variables and functions i.e. they specify which of the members are private and which of them are public. The class members that have been declared as private can be accessed only from within the class but public members can be accessed from outside of the class also. Using private declaration, data hiding is possible in C++ such that it will be safe from accidental manipulation. The use of keyword private is optional. By default, all the members are private. Usually, the data within a class is private and the functions are public. C++ provides a third visibility modifier, protected, which is used in inheritance. A member declared as protected is accessible by the member functions within its class and any class immediately derived from it. (The detail will be described in another chapter inheritance) A class binds data and functions together into a single class-type variable, known as encapsulation. Class Objects An Object is an instance of a class. Creating an object of a class is like defining a variable of a data type. Once a class has been declared, we can create variables of that type by using the class name. Syntax for creating an object is class_name object_name; e.g. box b1; // here box is assumed to be a class name The statement box b1; creates a variable b1 of type box. This variable b1 is known as object of the class box. Thus, class variables are known as objects. The objects can also be created when a class is defined by placing their names immediately after the closing braces like class box { private: .. public: }b1,b2,b3; But, this technique is rarely used in practice. Key differences between a class and its objects -Once we have defined a class, it exists all the time a program is running whereas objects may be created and destroyed at runtime. -For single class there may be any number of objects -A class has unique name, attributes, and methods. An object has identity, state, and behavior. Accessing class members: The private data or function of a class can be accessed only through the member function of that class. The member function can access all the data and functions as usual. The public class member can be accessed from outside the class also. The public class variable and function is accessed using object name and dot operator. Syntax for accessing public data member is Object_name.data_name;

20

Syntax for accessing public member function is Object_name.function_name(actual_argument_list); An example: #include<iostream.h> #include<conio.h> class rectangle { private: float len,br; public: void getdata(float l, float b) // defining member functions { len=l; br=b; } void calculate_area() { cout<<"\nThe area is "<<(len*br); }; void main() { rectangle r1, r2; // defining two objects clrscr(); r1.getdata(10,20); //accessing member function r2.getdata(15,10); r1.calculate_area(); r2.calculate_area(); } Output: The area is 200 The area is 150 Defining a member function A member function can be defined mainly in two ways: They are i) Member function inside the class body ii) Member function outside the class body a) Member Function Inside the class body In this case, a member function is defined at the time of its declaration. The function declaration is replaced by the function definition inside the class body. This technique is applied in the case of short functions. The function defined within a class body is treated as inline function. This is illustrated by following example. class box { private: float len, br, height; public: void get_data() //function definition { cout<<"Enter length, breadth, height"<<endl; cin>>len>>br>>height; } float volume() //function definition { return(len*br*height); } }; void main() { box b1; float result; clrscr(); b1.get_data(); result=b1.volume(); cout<<"The volume is:\t"<<result; } Output: Enter length, breadth, height 12 3 4 The volume is: 144 In this example, the functions get_data() and volume() are defined within body of class box. }

21

b) Member Function Outside the class body In this technique, only declaration is done within class body. The member function that has been declared inside a class has to be defined separately outside the class. The syntax for defining the member function is as return_type class_name :: function_name(argument_list) { //function body } Here, class_name:: is known as a membership identity label which tells the compiler which class the function belongs to (i.e. function_name belongs to class_name). The symbol :: is called scope resolution operator. An example: class box { private: float len, br, height; public: void get_data(); float volume(); }; void box::get_data() //function definition outside the class body { cout<<"Enter length, breadth, height"<<endl; cin>>len>>br>>height; } float box::volume() //function definition outside the class definition { return(len*br*height); } void main() { box b1; float result; b1.get_data(); result=b1.volume(); cout<<"The volume is:\t"<<result; } Output: Enter length, breadth, height 10 2 3 The volume is: 60 In this example, get_data() and volume() functions are member functions of class box. They are declared within class body and they are defined outside the class body. While defining member functions, box:: (membership identity label) specifies that member functions belong to the class box. Other are similar to normal function definition. Some characteristics of the member functions i. Several different classes can use the same function name (function overloading). The membership level will resolve their scope. ii. Member functions can access the private data of the class. A nonmember function can not do so. iii. A member function can call another member function directly, without using the dot operator. iv. A private member function can not be called by other function that is not a member of its class. Static class members Data members and member functions of a class in C++, may be qualified as static. We can have static data members and static member functions in a class. Static Data Members A data member can be made static by using prefix static. The default value for static data member is zero and other values can be initialized. The important property of such variable is that only one copy of that member is created for entire class and is shared by all the objects of the class. This type of variable is also called class variable. It is visible within the class but its life time is the entire program. The static data member differs from an ordinary data member in the following ways: i. Only a single copy of the static data member is used by all the objects, no matter how many objects are created. ii. It can be used within the class but its lifetime is the whole program. iii. It is initialized to zero when the first object of its class is created. Static data members are normally used to maintain values common to the entire class i.e. are useful when all objects of the same class must share a common item of information. For example, to use as a counter variable to count number of records as objects are created. For making a data member static, we require: i. Declare it within the class ii. Define it outside the class For example class student

22

{ static int count; //declaration within the class .. }; The static data member is defined outside the class as int student::count; //definition outside the class The definition outside the class is must. Example #include<iostream.h> #include<conio.h> class fruit { private: static int count; char name[15]; public: void get_name() { cout<<"\nEnter name of fruit\t"; cin>>name; } void display_name() { cout<<"\nThe name of apple\t"<<name; } void count_object() { count++; } void display_count() { cout<<"\nThe value of count i.e. no of objects "<<count; }; int fruit::count; //definition of static data member void main() { fruit m, a; m.get_name(); a.get_name(); m.display_name(); a.display_name(); m.count_object(); a.count_object(); m.display_count(); a.display_count(); } Output: Enter name of fruit mango Enter name of fruit apple The name of apple mango The name of apple apple The value of count i.e. no of objects 2 The value of count i.e. no of objects 2 The above example shows a variable count as static. This variable is shared by all objects (here 2 objects) and counts the number of objects. Static Member Function Like static data member, member function can be made static by using keyword static before function name. A static function can access to only other static data members or static member functions. Again, static member function can be called using the class name instead of object name. It is called as class_name:: function_name(argument_list); An example: class fruit { private: static int count; char name[15]; public: }

23

void get_name() { cout<<"\nEnter name of fruit\t"; cin>>name; } void display_name() { cout<<"\nThe name of apple\t"<<name; } void count_object() { count++; } static void display_count() { cout<<"\nThe value of count i.e. no of objects "<<count; }; int fruit::count; void main() { fruit m, a; m.get_name(); a.get_name(); m.display_name(); a.display_name(); m.count_object(); a.count_object(); fruit::display_count(); //accessing static member function } Output: Enter name of fruit banana Enter name of fruit apple The name of apple banana The name of apple apple The value of count i.e. no of objects 2 In C++, a static member function differs from the other member functions in the following ways: i. Only static members of the same class can be accessed by the static member function ii. It is called by using the name of the class rather than an abject as given below: name-of-the-class::function-name Array of Objects/Array of type class In c++, an array storing class type elements is called an array of objects. First we define a class and then array of objects are declared. class employee { char name[30]; float age; public: void getdata(); void putdata(); }; Here employee is a user defined data type and can be used to create objects that relate to different categories of the employees. e.g. employee manager[10]; employee worker[5]; The array manager contains 10 objects. An array of objects is stored inside the memory in the same way as multidimensional array. Example class employee { char name[30]; float age; public: void getdata(); void putdata(); }; void employee::getdata() { cout<<"Enter name:"; }

24

cin>>name; cout<<"Enter age:"; cin>>age; } void employee::putdata() { cout<<"NAME:"<<name<<endl<<"AGE:"<<age; } main() { const int size=5; int I; employee manager[size]; for(i=0;i<size;i++) { cout<<"Enter details of manager:"<<endl; manager[i].getdata(); } cout<<endl; for(i=0;i<size;i++) { cout<<"Details of manager:"<<endl; manager[i].putdata(); } getch(); }

Passing Object as argument An object can be passed into function as function argument like normal variables. This is illustrated from following example. This example shows addition of two complex numbers. #include<iostream.h> #include<conio.h> class complex { private: int real, imj; public: complex(){ real=0; imj=0; } Complex(int r, int i){ real = r; imj = i; } void add_complex(complex, complex); void display_complex(); }; void complex::display_complex() { cout<<"The sum is:\t" ; cout<<real<<"+j"<<imj; } void complex::add_complex( complex c1, complex c2) { real=c1.real+c2.real; imj=c1.imj+c2.imj; } void main() { complex first(10,20), second(20,30); complex result; clrscr(); cout<<"\nEnter first complex number\n"; first.get_complex(); cout<<"\nEnter second complex number\n"; second.get_complex(); result.add_complex(first,second);

25

result.display_complex(); getch(); } Output: Enter first complex number Real part: 2 Imj Part: 4 Enter second complex number Real part: 1 Imj Part: 8 The sum is: 3+j12 Returning Objects from Function A function can return object to the calling function as it can return integer, float. values. This can be explained as following example. Example #include<iostream.h> class distance { private: int feet; float inches; public: void get_distance(); distance add_distance(distance, distance); void display_distance(); }; void distance:: get_distance() { cout<<"Enter Feet:\t"; cin>>feet; cout<<"\nEnter Inches:\t"; cin>>inches; } void distance::display_distance() { cout<<"The sum is:\t" ; cout<<feet<<"\'-"<<inches<<'\"';

distance distance::add_distance( distance d1, distance d2) { distance sum; sum.inches=d1.inches+d2.inches; if(sum.inches>=12) { sum.inches-=12; sum.feet=1; } sum.feet+=(d1.feet+d2.feet); return (sum); //object return } void main() { distance first, second, result; cout<<"\nEnter first distance\n"; first.get_distance(); cout<<"\nEnter second distance\n"; second.get_distance(); result=result.add_distance(first,second); result.display_distance(); } Output: Enter first distance Enter Feet: 3 Enter Inches: 9 Enter second distance Enter Feet: 5 Enter Inches: 5 The sum is: 9'-2"

26

In this example, function add_distance() passes two objects as arguments and it returns value of type distance i.e. object of class distance. The returned object is stored in another object result in main() function.

27

Module 5 Constructors and Destructors Constructor A constructor is a special member function whose task is automatic initialization of an object of its class. It is special because its name is the same name of the same as the class name. The constructor is invoked automatically whenever an object of its associated class is created. It is called constructor because it constructs the values of the data member of the class. The rules for writing constructor functions or its characteristics are: A constructor name must be the same name as that of its class name. It is declared with no return type (not even void). It should have public or protected access within the class. They are invoked automatically when the objects are created. They cannot be inherited, though a derived class can call the base constructors. Like other C++ functions, they have default arguments. Constructors cannot be virtual, 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 operator new and delete when dynamic memory allocation is required.

Syntax class className { private: . public: className( ); . }; className :: className( ) { . } An example: class Test { private: int a; public: Test() //constructor { a=100; }

//constructor

//body of the constructor

void display() { cout<<"The value of data is\t :"<<a; } }; void main() { Test obj1,obj2; obj1.display(); obj2.display(); } Output: The value of the data is :100 The value of the data is :100 Declaration and Definition of a constructor It is defined like other member functions of the class i.e. either inside the class definition or outside the class definition. Above example shows constructor defined inside the class definition. The same constructor can also be defined as given below: class Test { private: int a; public: Test(); //only prototype here void display() { cout<<"The value of data is\t :"<<a; } }; Test::Test() //constructor definition outside the class definition

28

{ a=100; } void main() { Test obj1,obj2; obj1.display(); obj2.display(); } Types of Constructors i) Default Constructor A constructor without argument is known as default constructor. The constructor created in above example is the default constructor as it has no arguments. When the constructor is arguments then the initial values must be passed at the time of creation of the objects. Note: When there is no constructor defined in a class, the compiler automatically supplies a default constructor and if a constructor is declared with arguments it hides the default constructor. The default constructor supplied by the compiler does not do anything specific but initializes the data members by any dummy value when the objects are created. Example class complex { int rp; int ip; public: complex(); void show(); }; complex::complex() { rp=5; ip=6; } void complex::show() { cout<<rp<<"+i"<<ip; } main() { complex c1; c1.show(); getch(); } ii. Parameterized constructors The constructor Test(), defined above, initialized the data member of all the objects to 100. However, in practice it may be necessary to initialize the various data elements of 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. With the help of such a constructor the data elements of various objects can be initialized with different values. This is performed by passing different values to arguments of the constructor function while creating an object. A constructor may be defined with default arguments like function. The default constructor and constructor with default arguments are different things. Example Program to demonstrate the passing of arguments to the constructor (Parameterized Constructor) class rectangle { private: float length,breadth; public: rectangle(float l, float b) { length=l; breadth=b;

29

} void area() { cout<<"\nThe area of rectangle is:"<<length*breadth; } }; void main() { rectangle r1(10,20); //constructor call implicitly rectangle r2=rectangle(20,30); //constructor call explicitly r1.area(); r2.area(); getch(); } Output Of The Program The area of rectangle is:200 The area of rectangle is:600 Once we have declared a parameterized constructor, we must give initial values as arguments. If we do not do so, the compiler reports an error. For example: rectangle r; is not valid For passing initial values while creating an object, we can select any one of the following two ways: i. Call the constructor implicitly ii. Call the constructor explicitly In case i) we use like rectangle r1(10,20); It is also called shorthand method and it is used frequently In case ii) we use like rectangle r2=rectangle(20,30); here the constructor is called explicitly. iii. Copy constructors The constructor that creates new class object from the existing object of the same class is known as copy constructor. Copy constructors are always used when the compiler has to create a temporary object of a class object. The copy constructors are used when the initialization of an object is to be done by another object of the same class. The general format of the copy constructor is class_name(class_name &object) e.g. class copyConst { .. public: copyConst(copyConst &ob); }; Example: class sample { int id; public: sample (int x) { id=x;

//constructor again defined with passing arguments }

sample(sample & obj) //copy constructor { id=obj.id; } //copy in the value void display() { cout<<id; } }; void main() { sample ob1(100); // object a is created and initialized sample ob2(ob1); // copy constructor called sample ob3(ob2); // copy constructor called again cout<<"\nId of ob1: "; ob1.display(); cout<<"\nId of ob2: ";

30

ob2.display(); cout<<"\nId of ob3: "; ob3.display(); } Output: Id of ob1: 100 Id of ob2: 100 Id of ob3: 100 Note: i. A copy constructor takes a reference to an object of the same class as an argument. ii. If we do not pass the reference but the value as an argument to a copy constructor (for example sample(sample obj) instead of sample(sample & obj) in program )the compiler will give an error 'out of memory'. In case of pass by value the copy constructor keeps on calling itself repeatedly for creating copies of the objects. By passing reference, no such problem arises. When is a copy constructor called? A copy constructor may be called in the following situations: i. When an object is defined and initialized with other objects of the same class. ii. When we pass an object by value iii. In vase a function returns an object. Multiple constructors in a class (Overloaded Constructors) Besides performing the role of member data initialization, constructors are not different from other functions. This includes overloading also. When more than one constructor function are defined in a class, then we say that the constructor is overloaded. Example #include <iostream.h> #include <conio.h> class rectangle { private: float length,breadth; public: rectangle() //constructor declared without argument { length=0; breadth=0; } rectangle(float side) //constructor declared with one argument { length=side; breadth=side; } rectangle(float l,float b) //constructor declared with two arguments { length=l; breadth=b; } void calculateArea() { cout<<"\nThe area is\t :"<<(length*breadth); } }; void main() { rectangle r1; //call constructor rectangle() rectangle r2(10); //call constructor rectangle(float side) rectangle r3(10,30);//call constructor rectangle(float l, float b) r1.calculateArea(); r2.calculateArea(); r3.calculateArea(); getch();

31

} Output: The area is : 0 The area is The area is

: 100 : 300

Constructor with default arguments Like other member functions, constructor functions can use default arguments. The following code segment shows a constructor with default arguments. class add { int num1,num2,num3; public: add(int n1=0,int n2=0) { num1=n1; num2=n2; num3=0; } void sum() { num3=num1+num2; } void display() { cout<<"Sum is:"<<num3<<endl; } }; main() { add ob1; add ob2(5); add ob3(5,6); ob3.sum(); ob3.display(); getch(); } Note: Here, the default argument constructor can be invoked with either two or one or no parameter (s). But if there was another default constructor in a class like add() { } and we declare variable of type class like add o; then the declaration is ambiguous because there are two possible matches for this constructor. So, be careful in such cases and avoid such mistakes. Destructor 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 (~). A destructor is a function that automatically executed when an object is destroyed. Destructor functions get executed whenever an instance of the class to which it belongs goes out of existence. The primary usage of the destructor is to release space on the heap. A destructor function may be invoked explicitly. Rules for writing a destructor function are: A destructor function name is the same as that of the class it belongs except that the first character of the name must be tilde (~). It is declared with no return types (not even void) since it cannot ever return a value. It cannot be declared static. It takes no arguments and therefore cannot be overloaded. It should have public access in the class declaration. Syntax: ~className()

32

{.. .. } Example: class desTest { private: int a; public: desTest() { cout<<"\nI am within Constructor"; a=100; } ~desTest() { cout<<"\nI am within Destructor";} void display() {cout<<"\nValue of data is:"<<a;} }; void main() { desTest ob; Output: ob.display(); I am within Constructor getch(); } Value of data is:100 Another Example: int count=0; class alpha { public: alpha() //constructor function declaration { count++; cout<<"\nNumber of object created "<<count; } ~alpha() //destructor function declaration { cout<<"\nNumber of object destroyed "<<count; count--; }

I am within Destructor Output Enter Main Number of object created 1 Number of object created 2 Number of object created 3 Number of object created 4 Enter Block1 Number of object created 5 Number of object destroyed 5

}; void main() Enter Block2 { cout<<"\n\n Enter Main \n"; { Number of object created 5 alpha a1,a2,a3,a4;//creation of the objects Number of object destroyed 5 { cout<<"\n\nEnter Block1\n"; Re-Enter Main alpha a5; } { Number of object destroyed 4 cout<<"\n\nEnter Block2\n"; Number of object destroyed 3 alpha a6; Number of object destroyed 2 } cout<<"\n\nRe-Enter Main\n"; Number of object destroyed 1 } } As the objects are created and destroyed, they increase and decrease the count. Notice that after the first group of objects is created, a5 is created, and then destroyed; a6 is created, and then destroyed. Finally, the rest of the rest of the objects are also destroyed. When the

33

closing braces of a scope are encountered, the destructors for each object in the scope are called. Note that the objects are destroyed in the reverse order certain.

34

Module 6 Operator Overloading and Type Conversion Operator Overloading Introduction Operator overloading is one of the many exciting features of C++ language. C++ tries to make the user-defined data types behave in much the same way as the built in types. For instance, C++ permits us to add two variables of user-defined types with the same syntax that is applied to the basic types. This means that C++ has the ability to provide the operator with a special meaning for a data type. The mechanism of giving such special meanings to an operator is known as operator overloading. Programmers can use operators with user-defined types as well. Normally, a=b+c; works only with basic data types like int and float. However, using operator overloading, we can make this statement legal for user-defined data type also (like object). The use of + operator for two objects, means giving special meaning to + operator. The statement like C3.add_complex(C1,C2) can be converted into statement like C3=C1+C2 using operator overloading. Although C++ does not allow new operators to create, it does allow most existing operators to be overloaded so that when these operators are used with class objects, the operators have meaning appropriate to the new type. This is one of the C++ s most powerful features. Operator overloading contributes to C++ s extensibility, one of the languages most appealing attributes. Operator overloading is used when it makes a program clearer than accomplishing the same operations with explicit function calls. Excessive or inconsistent use of operator overloading is avoided as this can make a program cryptic and difficult to read. An operator is overloaded to perform the same function or similar function on class objects as the operators perform on objects of built in types. The main advantage of the operator overloading process in a program is that it much easier to read and debug. Defining operator overloading An operator overloading is defined with the help of a special function, called operator function, which describes the task to be done by the operator. The syntax for operator function is: return_type operator op(argument list); Where operator is keyword and op may be any valid operator to be overloaded. Thus, operator op is function name. Operator function may be either member function or friend function. A friend function will have only one argument for unary operators and two for binary operators while member function has no argument for unary and one for binary operators. The member function takes one less argument because, here, the object used to invoke the member function is passed implicitly and therefore available for the member function i.e. no argument for unary operator and only one argument for binary operator. Invocation of overloaded operator: a) Unary operator Overloaded operator function is invoked using expression op x or x op This is interpreted as For operator Function as friend Function: operator op(x) Binary operator Overloaded binary operator function is invoked using expression x op y This is interpreted as

i) ii)

For operator Function as member Function: x.operator op()

b)

i) ii)

For operator Function as member Function: x.operator op(y) For operator Function as friend Function: operator op(x,y)

Operator Overloading Restrictions create new operators such as $, @, etc. overridden.

Only those operators that are predefined in the C++ compiler can be used. User cannot The overloaded operator must have at least one operand that is of used defined type. The original meaning of overloaded operator is not changed. Overloaded operators follow the syntax rules of the original operators. They cannot be The operators sizeOf, :: (scope resolution), ?: (conditional) and .*(pointer to member)

operator can be overloaded. Friend function can not be used to overload operators =,(), [] and ->. Binary operators overloaded through a member function take one explicit argument and those which are overloaded through a friend function take two explicit arguments. When using binary operators overloaded through a member function, the left hand operand must be an object of the relevant class. Overloading Unary Operators:

35

An example: overloading of unary minus operator (i.e. -) #include <iostream.h> #include <conio.h> class opTest { int x,y,z; public: opTest(int a, int b, int c) { x=a; y=b; z=c; } void display(void) { cout<<x<<" "<<y<<" "<<z<<"\n"; } void operator-() { x=-x; Output of the program: y=-y; z=-z; The original object is: 10 -20 30 } The -ve of the object: -10 20 -30 }; void main() { opTest ob(10,-20,30); cout<<"The original object is: "; ob.display(); -ob; //activates operator -() function cout<<"The -ve of the object: "; ob.display(); getch(); } Example2: overloading of increment operator i.e. (++) class counter { unsigned int count; public: counter() //Constructor { count=0; } int getcount() //return count { return count; } void operator ++() //increment (prefix) { ++count; } }; void main() { counter c1,c2; //define and initialization cout<<"\nC1= "<<c1.getcount(); //display cout<<"\nC2= "<<c2.getcount(); //display ++c1; //c1.operator++(), incremant c1 ++c2; //incremant c2 ++c2; //incremant c2 cout<<"\nC1= "<<c1.getcount(); //display again cout<<"\nC2= "<<c2.getcount(); //display again getch(); Output of the above program }

C1=0 C2=0 C1=1 C2=2 Note: The ++ operator is applied once c1 and twice to c2.

36

You ca overload unary operator ++ and --. Further, they can be used as prefix or postfix. The general form for the prefix and postfix + + /-- operator functions are given below: return-type operator ++() { //Body of prefix operator } return-type operator ++(int) { //Body of postfix operator } Example3: Program to use increment counter variable with ++ operator using postfix and prefix notation class counter { int count; public: counter() //Constructor no argument { count=0; } void display() { cout<<count<<endl; } void operator ++() //increment (prefix) { ++count; } void operator ++(int) //increment (postfix) { count++; } }; void main() { counter c1; c1.display(); c1++; c1.display(); ++c1; c1.display(); getch(); }

//define and initialization //display 0 //post increment of c1 // display 1 //pre increment of c1 //display 2

Here, the member function for postfix function is similar to that of prefix, except that, by convention, it takes a single argument of type int in declaration i.e. counter operator ++(int). This int is not really an argument, but a signal to the compiler that we want to use postfix notation. Binary Operator Overloading Binary operators can be overloaded very easily like unary operators. Example1: Arithmetic operator (+) overloading for addition of two complex numbers class complex { private: float x, y; public: complex() { } // constructor1 without argument complex (float real, float imag) //constructor2 declared with two arguments { x=real;

37

y=imag; } complex operator+ (complex); //declaration of operator function void show(void) { cout<<x<<" + j "<<y<<endl; } }; complex complex::operator+(complex c) { complex temp; temp.x=x+c.x; temp.y=y+c.y; return (temp); // or simply return complex(x+c.x, y+c.y) } void main() { complex c1(2,4); //invoke Constructor2 complex c2(4,6); //invoke constructor2 complex c3; //invoke constructor1 c3=c1+c2; cout<<"c1="; c1.show(); Output of the program cout<<"c2="; c2.show(); c1=2 + j 4 cout<<"c3="; c2=4 + j 6 c3.show(); c3=6 + j 10 } In the above program, function receives only one complex type argument explicitly. It returns a complex type value, and it is a member function of class complex. In the overloading of binary operator, the left-hand operand is used to invoke the operator function and the right-hand operand is passed as an argument. Thus, C3=C1+C2 is equivalent to C3=C1.operator+(C2). Example2: Overloading of plus operator to concatenation of two strings #include<string.h> class string { private: char st[30]; public: string() { strcpy(st,""); } string(char input[]) { strcpy(st,input); } void display() {cout<<st;} string operator+(string secString) { string temp; strcpy(temp.st, st); strcat(temp.st, secString.st); return temp; } };

void main() { string S1("WelCome"); string S2(" To This College"); string S3;

Output of the program: S1=WelCome S2= To This College S3=WelCome To This College

38

S3=S1+S2; cout<<"S1="; S1.display(); cout<<"\nS2="; S2.display(); cout<<"\nS3="; S3.display(); getch(); } Example3: overloading of less than relational operator (i.e. <). enum boolean{false, true}; class distance { private: int feet, inch; public: distance() { feet=0;inch=0; } distance(int f, int i) { feet=f; inch=i; } void display() {cout<<feet<<"\'"<<inch<<'\"';} void getDist() { cout<<"Enter feet";cin>>feet; cout<<"Enter inches";cin>>inch; } boolean operator<(distance d2) { float f1=feet+(inch/12); float f2=d2.feet+(d2.inch/12); return((f1<f2)?true:false); } }; void main() { distance d1,d2; d1.getDist(); d2.getDist(); cout<<"\nDistance1=";d1.display(); cout<<"\nDistance2=";d2.display(); if(d1<d2) cout<<"\nDistance1 is less than distance2"; else cout<<"\nDistance1 is more than distance2"; } Overloading of assignment operators Example 4: Overloading += assignment operator #include <iostream.h> #include <conio.h> class Distance { private: int feet; float inches; public: Distance() { feet = 0; inches =0.0; }

Output of the program: First Run: Enter feet 3 Enter inches 5 Enter feet 7 Enter inches 9 Distance1=3'5" Distance2=7'9" Distance1 is less than distance2 Second Run: Enter feet 9 Enter inches 0 Enter feet 6 Enter inches 9 Distance1=9'0" Distance2=6'9" Distance1 is more than distance2

//constructor with no argument

39

};

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 << '\"'; } void operator +=(Distance);

//constructor with two arguments

//get length from user

//display distance

//add distance

void Distance::operator +=(Distance d) { feet += d.feet; inches += d.inches; if(inches>= 12.0) { inches -=12.0; feet++; } } void main() { Distance dist1; clrscr(); dist1.getdist(); Distance dist2(11,4.5); clrscr(); cout <<"\ndist1= "; dist1.showdist(); cout <<"dist2= "; dist2.showdist(); dist1 += dist2; cout << "\nAfter addition, "; cout << "\ndist1 = "; dist1.showdist(); } In this program we obtained a distance from the user, and add to it a second distance, initialized to 11-4.5 by the program. In this program the addition is carried out in main() with the statement dist1 += dist2; This cause the sum of dist1 and dist2 to be placed in dist1. In the operator +=() function, the object that takes on the value of the sum is the object of which the function is a member. Thus it is feet and inches that are given values, not temporary variables used only to return an object. The operator +=() function has no return value; it returns type void. A return value is not usually needed with arithmetic assignment operators like +=, because the result of the assignment operator is not assigned to anything. The operator is used, in the expression like the one in the program: dist1 += dist2; Adding polar coordinates Points on a plane are commonly specified with a pair of rectangular coordinates (x, y). Thus a point (5, 3) is located where x is 5 and y is 3 as shown in fig1.

3 2 1 0

(4, 3)

fig1

40

There is another way to describe a point on the plane: using polar coordinated of the form (radius, angle). In this system a line called radius, drawn from the origin to the point, and the angle this line makes with the positive X axis, specify the point as shown in fig2.

(r, a) radius =r angle = a

Fig2

Adding points in polar coordinates requires a three-step approach. First we convert the points to rectangular coordinates, then we add the points, and finally we convert the result back into polar coordinates. To convert from polar to rectangular, use the formulas: x = radius*cos(angle); y= radius*sin(angle); To convert back from rectangular to polar, use the formulas angle = atan(x/y); radius = sqrt(x*x + y*y); Here is a sample program that makes use of this three-step approach to add two points in polar coordinates. //Operator '+' with polar coordinates #include <math.h> #include <iostream.h> #include <conio.h> class Polar { private: float radius; float angle; float getx() { return radius*cos(angle); } float gety() { return radius*sin(angle); } public: Polar() { radius=0.0; angle=0.0; } Polar(float r, float a) {radius=r; angle=a; } void display(void) { cout<<"("<<radius<<","<<angle<<")"; } Polar operator +(Polar); }; Polar Polar::operator+(Polar p) { float x= getx() + p.getx();

41

float y=gety() + p.gety(); float r=sqrt(x*x+y*y); float a=atan(y/x); return Polar(r,a); } void main() { Polar p1(10.0,0.0); Polar p2(12.0,1.570796); Polar p3; p3=p1+ p2; clrscr(); cout<<"\np1:";p1.display(); cout<<"\np2:";p2.display(); cout<<"\np3:";p3.display(); } The Polar class contains two data items: radius and angle. Constructors in Polar initialize a variable to 0 or initialize it to specified values. Another member function displays these values. Two other member functions, getx() and gety(), convert polar coordinates to rectangular coordinates. The operator+() function adds two Polar variables. It does this by converting the Polar operands to rectangular coordinates, and adding the x coordinates to obtain x and y coordinates to obtain y. The x and y variables are then used to find the radius and angle of the sum, which is returned. Data Conversion It is the process of converting data from one type to another. In C++ by assignment statement we can do automatic type conversion for basic data type. For example: int i; float f=3.14; i=f; When we assign f to i, the f first converted into integer and then assigned to i. But compiler does not support automatic type conversion for user defined data types. But we can design the conversion routines for such data types if required. Following three types of conversion is possible for user defined data types: Conversion from basic type to class type (basic to object) Conversion from class type to basic type (object to basic) Conversion from one class type to another class type (object to object) i. Conversion From Basic to User defined data type In a statement like object1= integer1; a variable integer1 of standard data type (int) is assigned to a variable object1 of user defined data type (i.e. some class). This type of conversion is carried out by one argument constructor. An example #include <iostream.h> #include <conio.h> const float MTF=3.280833; class distance { int feet; float inches; public: distance() //constructor { feet=0; inches=0.0; } distance(float meters) //constructor with one argument { float floatfeet= MTF * meters; feet=int(floatfeet); inches=12*(floatfeet-feet); } void showdist() //display distances { cout<<feet<<"\' - "<<inches<<'\"'; } }; void main() { distance dist1=1.144,dist2; // uses 1 argument constructor to convert meter to distance

42

dist2=3.5; // uses 1 argument constructor dist1.showdist(); cout<<"\nDist2 = "; dist2.showdist(); getch(); }

cout<<"\nDist1 = ";

Output of the program: Dist1 = 3' - 9.039279" Dist2 = 11' - 5.794991"

Make a class called memory with member data to represent bytes, kilobytes, and megabytes. In your program, you should be able to use statements like m1=1087665; where m1 is an object of class memory and 1087665 is an integer representing some arbitrary number of bytes. Your program should display memory in a standard format like: 1 megabytes 38 kilobytes 177 bytes. class memory { int mega; int kilo; int byte; public: memory() {} memory(long int t) { long int temp; mega=t/(1024*1024); temp=t%(1024*1024); kilo=temp/1024; byte=temp%1024; } void print() { cout<<mega<<"megabytes"<<kilo<<"kilobytes"<<byte<<"bytes"<<endl; } }; main() { memory t1; long int mem=1087556; t1=mem; t1.print(); getch(); } ii. Conversion From User defined to Basic data type: C++ allows us to define an overloaded casting operator that could be used to covert a class type data to a basic type. Syntax for an overloaded casting operator function is: operator type_name() { } This function converts a class type (of which it is member) data to type_name. The casting operator function should satisfy following conditions. It must be a class member It must not specify a return type It must not have any arguments An example: const float MTF=3.280833; //meter to feet class distance { int feet; float inches; public: distance() //constructor { feet=0; inches=0.0; } distance(int ft, float in) { feet=ft; inches=in; } //constructor with two arguments

43

operator float() //conversion function { float ft; ft=inches/12; ft=ft+feet; return (ft/MTF); } void display() { cout<<feet<<"\' - "<<inches<<'\"'; } }; void main() { distance dist1(3,3.37); float mtrs; mtrs=dist1; //Uses conversion function to convert distance to meter cout<<"\nDistance in feet and inches = "<<endl; dist1.display(); cout<<"\nDistance in meters="<<mtrs<<"meters"; getch(); } Create a class called pwr that computes some number raised to some power. Store the result as a double. In your program you should be able to use statements like x=fourpowertwo; y=fourpowertwo+10.5 where x and y are of double and fourpowertwo is an object of class pwr. class pwr { float x,y; public: pwr(float a,float b) {x = a; y=b; } void display() { cout<<x<<"\t"<<y<<endl; } operator double() { double z; z=pow(x,y); return z; } }; main() { pwr fourpowertwo(8.0,2.0); double x,y; x=fourpowertwo; cout<<"result is:"<<x<<endl; y=fourpowertwo + 10.5; cout<<"result is:"<<y<<endl; getch(); } iii. Conversion between objects of Different Classes There may be some situations when we want to convert one class type data to another class type data. For example: objB=objA; Suppose objA is an object of class A and objB is an object of class B. We are converting the class A data type to class B type data and the value is assigned to objB. Here class A is known as source class and class B is known as destination class. The same two methods as same as conversion between basic types and user-defined types also apply to conversions between two userdefined types. That is, you can use a one-argument constructor, or you can use a conversion function. The choice depends on whether you want to put the conversion routine in the class specifier of the source object or of the destination object.

44

Routine in the source object When the conversion routine is in the source class, it is commonly accomplished using a conversion function. The two classes used in the next program are Rec and polar class. The Rec class is similar in that its objects are points in a two dimensional plane. However, it uses a rectangular coordinate system, where the location of each point is specified by x and y coordinates. Its member functions are similar to those for polar but are adapted to rectangular coordinates. //converts from polar to rec using routines in polar #include <math.h> #include <iostream.h> #include <conio.h> class Rec { private: float xco; float yco; public: Rec() { xco=0.0; yco=0.0; } Rec(float x, float y) { xco=x; yco=y; } void display() { cout<<"("<<xco<<","<<yco<<")"; } }; class Polar { private: float radius; float angle; public: Polar() { radius=0.0; angle=0.0; } Polar(float r, float a) { radius=r; angle=a; } void display(void) { cout<<"("<<radius<<","<<angle<<")"; } operator Rec(); }; Polar ::operator Rec() { float x= radius*cos(angle); float y= radius*sin(angle); return Rec(x,y); } void main() { Rec rec; Polar pol(10.0,0.785398); rec=pol; clrscr(); cout<<"\npol:";pol.display(); cout<<"\nrec:";rec.display(); }

45

We want to assign the value of the pol object to rec with the statement rec = pol; since these objects are from different classes, the assignment involves a conversion, and- as we specified- in this program the conversion function is a member of the Polar class: Polar ::operator Rec() { float x= radius*cos(angle); float y= radius*sin(angle); return Rec(x,y); } This function transforms the object, which main() then assigns to rec.

Routine in destination object When the conversion routine is in the destination class, we use a one-argument constructor. However, things are complicated by the fact that the constructor in the destination class must be able to access the data in source class to perform the conversion. The polar data radius & angle are private, so we must provide special function to allow direct access it. //converts from polar to rec using routines in polar #include <math.h> #include <iostream.h> #include <conio.h> class Polar { private: float radius; float angle; public: Polar() {radius=0.0; angle=0.0; } Polar(float r, float a) { radius=r; angle=a; } void display(void) { cout<<"("<<radius<<","<<angle<<")"; } float getr() { return radius; } float geta() { return angle; } }; class Rec { private: float xco; float yco; public: Rec() { xco=0.0; yco=0.0; } Rec(float x, float y) { xco=x; yco=y;

46

} void display() { cout<<"("<<xco<<","<<yco<<")"; } Rec(Polar p) { float r=p.getr(); float a=p.geta(); xco=r*cos(a); yco=r*sin(a); } }; void main() { Rec rec; Polar pol(10.0,0.785398); rec=pol; clrscr(); cout<<"\npol:";pol.display(); cout<<"\nrec:";rec.display(); } Heres the conversion routine, a one-argument constructor, from the Rec class: Rec(Polar p) { float r=p.getr(); float a=p.geta(); xco=r*cos(a); yco=r*sin(a); } This function sets the object of which it is a member to the rectangular coordinates that correspond to the polar coordinates of the object received as an argument.

Module 7 INHERITANCE Introduction (base class and derived class) An important feature of OOP is reusability. If an existing thing can be reused without creating it again, we can save both time and money. In doing so very little efforts are made and programs reliability is increased as the class being reused has already been tested and debugged. C++ supports the concept of reusability via inheritance. Inheritance is the capability of one class to inherit properties from an existing class. The new derived classes are called sub classes or derived classes and the old class is known as the base class or super class. The derived class inherits the properties of the base class, including the member functions. Without redefining the old class, we can add new properties to the derived class and even inherited class member functions can be redefined. Needs and objectives of inheritance The major needs and objectives of the inheritance are: i. It ensures the closeness with the real world models. ii. It extends the functionality of the existing class. iii. It establishes "a kind of" relationship. iv. It helps in reuse of an existing class by a subclass (reusability) v. The redundancy can be reduced by abstracting a super class from few subclasses. Types of Inheritance In C++, any class can be a base class. More than one class can be derived from a single base class, and a derived class can be base class to another class or classes. Different types of inheritance are given below: 1. Single Inheritance When a derived class inherits only from one base class, it is known as single inheritance, as shown in figure below. Base class

47

Derived class Fig: Single Inheritance Features:

o o o o

Derived class has only one direct base class Creates simple hierarchy of classes - trees One to one inheritance of members Specializes a base class

2. Multiple Inheritance When a derived class inherits from multiple base classes, it is known as multiple inheritance, as shown in figure below.

Base classes

Derived class Fig: Multiple Inheritance Features

C
o o o o
Derived class has more than one direct base class Creates complex hierarchy of classes - graphs Possible multiple inheritance of members Combines multiple classes class D : public A, public B { };

Same Inheritance and Access Rules

Derived class contains all members from all base classes Regardless of access mode

3. Hierarchical Inheritance When the properties of one class are inherited by more than one class, it is known as hierarchical inheritance, as shown in figure below.

Base class

Derived classes

C Fig: Hierarchical Inheritance

4. Multilevel Inheritance When a derived class inherits from a class that itself is inherited from another class, it is known as multilevel inheritance, as shown in figure below.

Base class of B Base class of C Derived class of A

B
Fig: Multilevel Inheritance

Derived class of B

5. Hybrid Inheritance A When a derived class inherits from multiple base classes and all of its base classes inherit from a single base class, this form of inheritance is known as hybrid inheritance, as shown in figure below. Base class

C 48 D

Derived class

of A

Derived class

of A

Derived class of B,C Fig: Hybrid Inheritance Defining derived classes In C++, a derived class has to identify the class from which it is derived in addition to its own details. The syntax of defining a derived class (using single inheritance) is shown below: class derived_classname: visibility_mode base_classname { . //members of derived class . }; Here the colon (:) indicates that the derived_classname is derived from the base_classname, the visibility_mode may be either private or public or protected. The default visibility mode is private. The visibility mode controls the visibility and availability of the inherited base class members in the derived class. For example, class ABC //base class { .. //members of ABC .. }; class XYZ: private ABC //private derivation { .. //members of XYZ .. }; class XYZ: public ABC // public derivation { .. //members of XYZ .. }; class XYZ: protected ABC // protected derivation { .. //members of XYZ .. }; class XYZ: ABC // private derivation by default { .. //members of XYZ .. }; A derived class inherits all the members of a base class but the derived class has access privilege only to the non private members of its base class. We can add our own data and member functions in the derived class and the functionality of the base class is extended. Visibility modes Visibility modes control the access specifier to be inheritable members of the base class in the derived class. There are 3 visibility modes: Private visibility mode When the visibility mode is private, the derived class can access the public and protected members of the base class privately. The public and protected members of the base class are private members of the derived class with private visibility mode i.e., the inherited members can be accessed only through member functions of the derived class. If we want to inherit these inherited members further we can not do so because private members are not inheritable. The following program segment illustrates this concept. class ABC //Base class { private: int a; void enter1(); public: int b; void show1(); protected: int c; void compare1(); };

49

class XYZ: private ABC // privately derived class XYZ { private: int x; void enter2(); public: int y; void show2(); protected: int z; void compare2(); }; Using concept of private derivation members of class ABC and XYZ are stored as Class ABC Class XYZ private: a enter1( ) public: b show1( ) protected: c compare1( ) private: x, b, c enter2( ), show1( ), compare1( ) public: y show2( ) protected: z compare2( )

Public visibility mode When the visibility mode is public, the derived class can access the public and protected members of the base class publically. The public members of the base class become the public members of the derived class, and the protected members of the base class become the protected members of the derived class. The following program segment illustrates this concept. class ABC //Base class { private: int a; void enter1(); public: int b; void show1(); protected: int c; void compare1(); }; class XYZ: public ABC // publically derived class XYZ { private: int x; void enter2(); public: int y; void show2(); protected: int z; void compare2(); }; Using concept of public derivation members of class ABC and XYZ are stored as Class ABC Class XYZ private: a enter1( ) public: b show1( ) protected: c compare1( ) Protected visibility mode private: x enter2( ) public: b, y show1( ), show2( ) protected: c, z compare1( ), compare2( )

50

When the visibility mode is protected, the derived class can access the public and protected members of the base class protectedly. The public and protected members of the base class become the protected members of the derived class. The following program segment illustrates this concept. class ABC //Base class { private: int a; void enter1(); public: int b; void show1(); protected: int c; void compare1(); }; class XYZ: protected ABC // protectedly derived class XYZ { private: int x; void enter2(); public: int y; void show2(); protected: int z; void compare2(); }; Using concept of protected derivation members of class ABC and XYZ are stored as Class ABC Class XYZ private: a enter1( ) public: b show1( ) protected: c compare1( ) Summary of Base class access inheritance rules Base Class Private Member Public Member Protected Member Private Derived not inheritable private private Public Derived not inheritable public protected Protected Derived not inheritable protected protected private: x enter2( ) public: y show2( ) protected: c, y, z compare1( ), show1( ), compare2( )

Single Inheritance If a derived class has only one base class or superclass then this type of inheritance is known as single inheritance. Syntax class X { .. // base class members }; class Y: public X { //Y derived from X }; The following program illustrates the concept of single inheritance using public derivation. Create a class called rectangle with member data to represent length, breadth, and area. Use appropriate member functions to read length and breadth from user and to calculate area of a rectangle. Next create a derived class called box from the class rectangle. Use appropriate member functions to read height and to calculate volume of the box.

51

class rectangle //base class { int area; //private data not inheritable protected: int length; int breadth; public: void read() { cout<<"Enter length and breadth:"<<endl; cin>>length>>breadth; } void areacal() { area=length*breadth; cout<<"AREA="<<area<<endl; } }; class box:public rectangle //public derivation { private: int height; float volume; public: void readh() { cout<<"Enter height:"<<endl; cin>>height; } void calvol() { volume=length*breadth*height; cout<<"VOLUME="<<volume<<endl; } }; main() { rectangle r; //object of base class r.read(); r.areacal(); box b; //object of derived class b.read(); //call of derived function using derived class object b.readh(); b.calvol(); getch(); } In the above program base class rectangle contains private data area which is not inheritable but the data and member functions in protected and public area are inheritable and are inherited to derived class box. So, it is possible to use derived data and member functions using object of derived class. The single level inheritance is also allowed using the other two visibility modes i.e. private and protected. Multilevel Inheritance When derived class itself acts as a base class of another one, this is called multilevel Inheritance. Syntax class X { .. // base class members }; class Y: public X { //Y derived from X }; class Z: public Y { .. //Z derived from Y }; The following program illustrates the concept of single inheritance using public derivation.

52

Create a class called student with two member data name, roll. Derive a class marks from student that has additional data members sessional1, sessional2 to store sessional marks. Derive another class result from marks and add the sessional marks. Use appropriate member functions to read and display data in the class. class student { protected: char name[30]; int roll; public: void getdata() { cout<<"Enter name:"; cin>>name; cout<<"Enter rollno:"; cin>>roll; } void displaydata() { cout<<"NAME:"<<name<<endl<<"ROLLNO:"<<roll<<endl; } }; class marks: public student { protected: float sessional1; float sessional2; public: void getmarks() { cout<<"Enter sessional marks:"; cin>>sessional1>>sessional2; } void showmarks() { cout<<"SESSIONAL1="<<sessional1<<endl<<"SESSIONAL2="<<sessional2<<endl; } }; classs result:public marks { float total; public: void totalmarks() { total=sessional1+sessional2; cout<<"Total="<<total<<endl; } }; void main() { result r1; //object of derived class result r1.getdata(); r1.getmarks(); cout<<"The record of the student is:"<<endl; r1.displaydata(); r1.showmarks(); r1.totalmarks(); getch(); } Multiple Inheritance When a subclass inherits from multiple base classes, it is known as multiple inheritance. A suitable example of multiple inheritance is the child inheriting characteristics of the parents. Multiple inheritance allows us to combine the features of several existing classes into a derived class. The syntax of derived class with multiple base classes is: class derived:visibility_mode base1, base2, { // body of derived class

53

}; where visibility mode may be either public, private or protected and the base classes are separated by commas. The following program illustrates the concept of multiple inheritance: #include<iostream.h> #include<conio.h> class ONE { protected: int x; // to make it available to the derived class public: void display1() { cout<<x<<"\n"; } }; class TWO { protected: int y; // to make it available to the derived class public: void display2() { cout<<y<<endl; } }; class derived: public ONE, public TWO { public: void enter(int a, int b) { x=a; y=b; } }; main() { int v1,v2; derived obj; cout<<"Enter two integer values:"; cin>>v1>>v2; obj.enter(v1,v2); cout<<"You have entered:"<<endl; obj.display1(); obj.display2(); getch(); } Ambiguities in Multiple Inheritance A lot of ambiguities can occur when a class inherits from multiple base classes. It may occur when a class inherits from multiple base classes. It may occur when Two or more than two base classes have a function of identical name (Ambiguity due to function name) Ambiguity due to data member Ambiguity due to Function Name Consider the following program #include<iostream.h> #include<conio.h> class A { protected: int a; public: void read() { cout<<"enter A:"; cin>>a; }

54

}; class B: public A { protected: int b; public: void read() { cout<<"Enter b:"; cin>>b; } }; class C: public A { protected: int c; public: void read() { cout<<"Enter c:"; cin>>c; } }; class D:public B,public C { int total; public: void add() { total=a+b+c; cout<<total; } }; main() { D d; d.read(); d.add(); getch(); } Here while calling read( ) function with object d of class D, first it try to invoke the read() function of its own class. But it will not find read() function of its own class, but there are two read function derived from class B and Class C, which creates ambiguity. This is the case of ambiguity due to function name This can be resolved in two ways:

i) By overriding member function as follows (i.e. we can redefine the members in the derived class) #include<iostream.h> #include<conio.h> class A { protected: int a; public: void read() { cout<<"enter A:"; cin>>a; } }; class B:virtual public A { protected: int b; public: void read() { cout<<"Enter b:";

55

cin>>b; } }; class C:virtual public A { protected: int c; public: void read() { cout<<"Enter c:"; cin>>c; } }; class D:public B,public C { int total; public: void read() { A::read(); B::read(); C::read(); } void add() { total=a+b+c; cout<<total; } }; main() { D d; d.read(); d.add(); getch(); } ii) By using scope resolution operator as follows (i.e. we can use scope resolution operator to call the required function as d.A::read(); calls the read() function of class A) #include<iostream.h> #include<conio.h> class A { protected: int a; public: void read() { cout<<"enter A:"; cin>>a; } }; class B:virtual public A { protected: int b; public: void read() { cout<<"Enter b:"; cin>>b; } }; class C:virtual public A { protected: int c; public:

56

void read() { cout<<"Enter c:"; cin>>c; } }; class D:public B,public C { int total; public: void add() { total=a+b+c; cout<<total; } }; main() { D d; d.A::read(); //call read of class A d.B::read(); //call read of class B d.C::read(); //call read of class C d.add(); getch(); } In the above program ambiguity arises due to data member also which is resolved by using virtual base class. By using virtual base class only one copy of data member is inherited. Ambiguity due to data member In multiple Inheritance, another ambiguity may arise due to multiple copies of the same base class being inherited in the derived class. For example,

ONE

ONE

TWO

THREE

Here, class FOUR inherits from two base classes, TWO and THREE which have been derived from class ONE. So the base class FOUR has two copies of ONE. The following program illustrates this fact: #include<iostream.h> #include<conio.h> class ONE { public: float a; }; class TWO: public ONE { public: float b; }; class THREE: public ONE { public: float c; }; class FOUR: public TWO, public THREE { public: float d; }; main()

FOUR

57

{ FOUR obj; //object of derived class FOUR declared obj.a= = 32.11; //ambiguous because we are having two copies of variable a through class getch(); // TWO and THREE } We can resolve this ambiguity in two ways. i) By using scope resolution operator The following program illustrates this concept: #include<iostream.h> #include<conio.h> class ONE { public: float a; }; class TWO: public ONE { public: float b; }; class THREE: public ONE { public: float c; }; class FOUR: public TWO, public THREE { public: float d; }; main() { FOUR obj; //object of derived class FOUR declared obj.TWO::a= = 32.11 ; // a inherited from TWO obj.THREE::a= = 32.33; //a inherited from THREE getch(); } ii) By using Virtual Base Classes In C++, by making a class virtual, only one copy of that class inherited though we may have many inheritance paths between the virtual base class and a derived class. We can specify a base class inheritance by using the keyword virtual. The following program illustrates the concept of virtual base class: #include<iostream.h> #include<conio.h> class ONE { public: float a; }; class TWO: virtual public ONE //TWO inherits ONE as virtual { public: float b; }; class THREE: virtual public ONE //THREE inherits ONE as virtual { public: float c; }; class FOUR: public TWO, public THREE // only single copy of ONE inherited to FOUR { public: float d; }; main() { FOUR obj; //object of derived class FOUR declared obj.a= = 32.11; // no ambiguity now

58

obj.b= = 35.63 getch(); } Here classes TWO and THREE inherit from class ONE by using the keyword virtual. Class ONE is the virtual base class so class FOUR inherits only one copy of data member 'a' from class ONE. So the objects of class FOUR can use data member 'a' without any ambiguity. Hierarchical Inheritance When the properties of one class are inherited by more than one class, it is known as hierarchical inheritance. The following program illustrates this concept. Create a class student with two member data to represent name and age of the student. Use member functions to read and print these data. From this class, derive a class called boarder with a member data to represent a room number. Derive another class called day-scholar from the class student with a member data to represent address of the student. In both derived classes, use member functions to read and print the respective data. #include<iostream.h> #include<conio.h> class student { protected: char name[30]; int age; public: void read() { cout<<"Enter name:"; cin>>name; cout<<"Enter age:"; cin>>age; } void display() { cout<<"NAME:"<<name<<endl<<"AGE:"<<age<<endl; } }; class boarder: public student { protected: int roomno; public: void readroom() { cout<<"Enter room number:"<<endl; cin>>roomno; } void printroom() { cout<<"RoomNo:"<<roomno; } }; class dayscholar: public student { protected: char address[50]; public: void getaddress() { cout<<"Enter Address:"<<endl; cin>>address; } void printaddress() { cout<<"Address:"<<address; } }; void main() { dayscholar s; boarder d; s.read();

59

d.readroom(); s.getaddress(); s.display(); d.printroom(); s.printaddress(); getch(); } Hybrid Inheritance It is the combination of more than one type of inheritance. Following program illustrates this concept. class B1 { protected: int x; public: void assignx() { x=20; } }; class D1: public B1 { protected: int y; public: void assigny() { y=40; } }; class D2: public D1 { protected: int z; public: void assignz() { z=60; } }; class B2 { protected: int k; public: void assignk() { k=80; } }; class D3: public B2, public D2 { private: int total; public: void output() { total=x+y+z+k; cout<<"Total is:"<<total<<endl; }; }; void main() { D3 d; d.assignx(); d.assigny(); d.assignz(); d.assignk(); d.output();

60

getch(); } Above program is the combination of multilevel inheritance and multiple inheritance. Containership/Nesting of classes In C++, a class derive certain features of another class through inheritance. The other way is that we can define a class within another class called nesting of classes. For example, class ONE { // member data and functions }; class TWO { // member data and functions }; class THREE { ONE obj1; //object of class ONE TWO obj2; // object of class TWO }; This above shown relationship is called containership or nesting. In this case the constructors of all the members objects are called before its own constructor body is executed. Example class generalinfo { char name[50]; int age; char address[50]; public: void read() { cin>>name>>age>>address; } void display() { cout<<NAME:"<<name<<"AGE:"<<age<<"ADDRESS:"<<address<<endl; } }; class academicinfo { char degree[50]; generalinfo g; public: void read() { g.read(); cout<<"Enter degree:"; cin>>degree; } void display() { g.display(); cout<<"Degree:"<<degree; } }; class employee { char status[50]; generalinfo g; academicinfo a; public: void read() { a.read(); cout<<"Enter Status:"; cin>>status;

61

} void display() { a.display(); cout<<endl; cout<<"Status:"<<status; } }; main() { employee e; e.read(); cout<<endl; e.display(); getch(); } Overriding member Function A base class member can be overridden by defining a class member having the same name as that of the base class member in C++. The following program illustrates this concept. #include<iostream.h> #include<conio.h> class base { public: void display() { cout<<"\n Base class display function invoked\n"; } }; class derived: public base { public: void display() { cout<<"\n Derived class display function invoked\n"; } }; void main() { derived obj; obj.display(); getch(); } The output of the above program would be Derived class display function invoked Here the function display() in class base has been overridden by declaring it again in class derived. If the function with same name exists in both the derived and the base class compiler decides the function call as follows: The function in the derived class is executed, if it is called by an object of the derived class ii. The function in the base class is executed, if it is called by an object of the base class. Passing parameters to base class constructor (Constructors in Derived classes) General format for calling a base class constructor from a derived class constructor is: derivedclass-constructor(argument list): baseclass-constructor(argument list) { // code } e.g. class test { int count; public: test() { count=0; } test(int x) { int x;

62

} void display() { cout<<"Count="<<count; } void operator++() { count++; } }; class test1: public test { public: test1():test() { } test1(int a): test(a) { } }; main() { test1 p; test1 q(100); p.display(); q.display(); p++; q++; p.display(); q.display(); getch(); } Example 2 class base { protected: int i; public: base(int x) { i=x; } }; class derived:public base { int j; public: derived(int x, int y):base(y) { j=x; // derived uses x and y is passed along to base } void show() { cout<<i<<"\t"<<j<<endl; } }; void main() { derived obj(3,4); obj.show(); getch(); } Here derived's constructor is declared as taking two parameters x and y. However, derived uses only x; y is passed along to base. In general, the derived class constructor must declare both the parameters that it requires as well as any required by the base class.

63

Module 8 VIRTUAL FUNCTION AND RUN TIME POLYMORPHISM Polymorphism is one of the crucial features of object oriented programming. It allows us to have many versions of a method, each implementations defined in a different class. We have already seen implementation of overloaded functions and operators which support compile time polymorphism or early binding. Run time polymorphism can be achieved by using virtual functions. Types of polymorphism: a) Compile time polymorphism- Overloading of functions, overloading of operators b) Run time polymorphism- Virtual functions Friend Functions and Friend Classes A function is made to be friend of a class by using keyword friend before function declaration within class body. The friend function can access private data of the class for which it is declared as friend, although it is not member function of the class. The function definition doesnt use either keyword friend or the scope resolution operator. A function can be declared as friend in any number of classes. Characteristics of Friend Function: Although friend function is not member function, it has full access to the private data of the class. Friend Function is called like a normal function without the help of any object. While using member data or functions, it uses object name and dot membership operator with each member name Usually, it has objects as arguments. Member function of one class can be friend function of another class. In such case, the member function is defined using the scope resolution operator. As class X {. int function1(); }; class Y{. friend int X:: function1(); }; Example for friend function: class friendTest { float first,second; public: void get_value() { cout<<"Enter two numbers"<<endl; cin>>first>>second; } friend float calculate_mean(friendTest s); }; float calculate_mean(friendTest s) { return((s.first+s.second)/2.0); }

void main() { friendTest x; x.get_value(); cout<<"Mean of these two numbers is "<<calculate_mean(x); } A class can be declared as friend class of other such that all the member functions of one class are friend functions of later class. An example: class X { float first,second; public: void get_value() { cout<<"Enter two numbers"<<endl; cin>>first>>second; } friend class Y; }; class Y { public: void display_data(X obj) {cout<<"\nThe first number is: "<<obj.first<<"\nThe second number is: <<obj.second; }

64

}; void main() { X x; Y y; x.get_value(); y.display_data(x); } this pointer: In addition to the explicit parameters in their argument lists, every class member function (method) receives an additional hidden parameter, the "this" pointer. The "this" pointer addresses the object on which the method was called. Thus, this pointer is used as a pointer to the class object instance by the member function. Each object maintains its own set of data members, but all objects of a class share a single set of methods. This is, a single copy of each method exists within the machine code that is the output of compilation and linking. A natural question is then if only a single copy of each method exists, and its used by multiple objects, how are the proper data members accessed and updated. The compiler uses the "this" pointer to internally reference the data members of a particular object. Suppose, we have an Employee class that contains a salary member and a setSalary method to update it. Now, suppose that two Employees are instantiated. class Employee { private: double salary; public: void setSalary(double sal) { salary = sal; } void display() { cout<<"\nThe salary:"<<salary; } }; int main() { Employee programmer; Employee managar; managar.setSalary(60000.0); programmer.setSalary(40000.0); managar.display(); programmer.display(); } If only one setSalary method exists within the binary that is running, how is the correct Employee's salary updated? The compiler uses the "this" pointer to correctly identify the object and its members. During compilation, the compiler inserts code for the "this" pointer into the function. The setSalary method that actually runs is similar to the following pseudo-code. void setSalary(Employee *this, float sal) { this->salary = sal; } The correct object is identified via the "this" pointer. Example: This example show the use of this for displaying starting address of object class this_example { private: int a; float data; public: void address() // display address of the object which calls the function { cout<<"\nThe address of object is "<<this; } }; void main() { this_example obj1, obj2; obj1.address(); obj2.address();

65

} Output: The address of object is 0x8fd3fff0 The address of object is 0x8fd3ffea Example: This example shows the use this pointer #include<iostream.h> #include<conio.h> class this_pointer_example { int data1; public: int getdata() //Function using this pointer for C++ Tutorial { return this->data1; } void setdata(int newval) //Function without using this pointer { this->data1 = newval; } //same as data1=newval; }; void main() { int result; this_pointer_example obj; obj.setdata(10); result=obj.getdata(); cout<<"\nThe result is: "<<result;; } Output: The result is 10 Characteristics of this pointer: this pointer stores the address of the class instance, to enable pointer access of the members to the member functions of the class. this pointers are not accessible for static member functions.

this pointers are not modifiable.

new and delete Operators As we know that the process of allocating and freeing memory at run time is called Dynamic Memory Allocation. This conserves the memory required by the program and returns this valuable resource to the system once the use of reserved space is utilized. In C, the functions like calloc(), malloc(), free(), realloc() are used for memory management at run time. C++ supports two new unary operators new and delete for memory management at run time along with these Cs functions. An object can be created by using new and destroyed by using delete. Syntax for new: pointer_variable=new data_type; Where pointer_variable is predefined pointer of type data_type and data_type is user-defined or built in data type of C++. The new operator allocates sufficient memory to hold a data object of type data_type and returns the address of the object. The pointer variable holds the starting address of allocated memory. Examples: int *ptr; ptr=new int; The above statement allocates two bytes of memory and is stored by pointer variable ptr. Characteristics:

Memory can be initialized using new operator. This is done as Pointer _variable= new data_type(initial_value); e.g. int *p; p=new int(35); will allocates two bytes of memory and 35 is allocated at this memory initially. new can be used to allocate a memory space for data types including user defined types such as arrays, structures and classes. Its syntax is pointer_variable=new data_type[size]; // for array e.g. int *p; p=new int[100]; will allocates 200 bytes memory and starting address is stored at pointer variable p.

Advantages of new operator over the function malloc()

66

It automatically computes the size of the data object while we need to use sizeof operator in the case of malloc() function. It is possible to initialize the object while creating the memory space. It automatically returns the correct pointer type, so that there is no need to use a type caste. In syntax of malloc() function ptr_variable=(data_type*) malloc(size_of_block); data_type within () is for type casting which is not needed in the case of new operator. delete: If a program reserves many chunks of memory using new, eventually all the available memory will be reserved and the system will crash. To ensure safe and efficient use of memory, the new operator is matched by a corresponding delete operator. This operator returns the memory to the operating system when a data object in no longer needed. Thus, delete operator is used to release the memory space for reuse by destroying the object when it is no longer needed. The syntax delete pointer-variable; // general syntax delete [] pointer-variable; // in case of array An example, a program which asks for a number of students at run time and according to the number of students in a class, the program reserves the memory to store percentage of each student and finally calculates average percentage of class. #include<iostream.h> #include<conio.h> void main() { clrscr(); int num,*ptr; float sum=0; cout<<"How many number of students?"<<endl; cin>>num; ptr=new int[num]; cout<<"Enter each students marks"<<endl; for(int i=0;i<num;i++) { cin>>*(ptr+i); sum+=*(ptr+i); } float avg= sum/num; cout<<"The average is "<<avg; delete []ptr; getch(); }

67

Module 9 DATA STRUCTURES STACK A stack is an ordered collection of items into which new items may be inserted and from which items may be deleted at one end, called the top of the stack. A stack is a linear data structure in which data is inserted and deleted at one end (same end) i.e data is stored and retrieved in a Last In First Out (LIFO) order. The most recently arrived data item is the first one to depart from a stack. The definition specifies that a single end of the stack is designated as the top of the stack. The new items may be put on the top of the stack (in which case the top of the stack moves upward to correspond to the new highest element) or item which are at the top of the stack may be removed (in which case the top of the stack moves downward to correspond to the new highest element)

A common model of a stack is a plate or coin stacker. Plates are "pushed" onto to the top and "popped" off the top. Figure below shows various stages of stack top during insertion and deletion:

top top top top Stack Empty 20 30 20

40 30 20

Insertion of first element

Insertion of second element Insertion of third element

Figure (a) Stack top increases during Insertion

40 30 20 Stack initially

top 30 20 40 deleted Top 20 30 deleted top top 20 deleted

Figure (b) Stack top decreases during deletion Operations on Stack The basic operations that can be performed on stack are as follows: i) PUSH operation ii) POP operation PUSH operation The process of adding new element to the top of the stack is called PUSH operation. When an item is added to stack it is said to be pushed on the stack. Pushing an element in the stack involve adding of element, so after every PUSH operation the top is incremented by one as the new element will be inserted at the top. The PUSH operation is applicable to any stack which is not full. If the stack full the items cannot be pushed. If the stack is full, it is called STACK OVERFLOW condition. Algorithm for PUSH operation

68

Declare an array large enough to hold the data of the stack Declare a variable top and initialize it to -1 Check whether the stack is full If the stack is full print the stack overflow message and terminate the program If the stack is not full, increment the value of top by 1 Insert the data at the top of the stack Exit. Let stack[maxsize] is an array for implementing the stack i. Check for stack overflow if top=maxsize-1, then print stack overflow message and exit ii. Set top=top+1 i.e. increase top by 1 iii. Set stack[top]=data i.e. insert data in new top position iv. Exit. Stack Overflow: This is the situation when the stack is full and no more elements can be pushed onto the stack. POP operation The process of deleting an element from the top of the stack is called POP operation. When an item is removed from the stack it is said to be popped from the stack. If the stack contains a single item and stack is popped, the resulting stack contains no items and is called empty stack. The POP operation can not be applied to the empty stack because such stack has no element on top. If there is no element on the stack and the POP operation is performed then this will result into stack underflow condition. Stack underflow: This is the situation when the stack is empty and no more element can be poped from the stack. Algorithm for POP operation 1. Check whether the stack is empty 2. If the stack is empty print the stack underflow message and terminate the program 3. If the stack is not empty remove the element at the top of the stack 4. Decrease the value of top by 1 5. Exit i. Check for the stack underflow if top<0 then print "STCK IS EMPTY" and exit else remove the top element at the top of the stack ii. Decrement the stack top set top=top-1 iii. Exit. Source Code #include<iostream.h> #include<conio.h> # define size 5 class stack { int top; int item[size]; public: stack() { top=-1; } void push(int); int pop(); void display(); }; void stack::push(int x) { if(top!=size-1) { top++; item[top]=x; } else

69

cout<<"Stack Overflow"<<endl; }

int stack::pop() { int x; if(top!=-1) { x=item[top]; top--; return x; } else cout<<"Stack Underflow"; return 0; } void stack::display() { cout<<"Stack content is:"<<endl; for(int i=0;i<=top;i++) cout<<item[i]<<endl; } main() { stack s; s.push(10); s.push(20); s.display(); s.pop(); s.display(); getch(); } Observe the output of the above program by using push and pop operations. QUEUE In ordinary English a queue is defined as a waiting line, like a line of people waiting to purchase tickets where the first person in the line is the first person served. For computer applications we similarly define a queue to be a list in which all additions to the list are made at one end and all deletion from the list are made at the other end. A queue is an ordered collection of items in which new element are added at one end called the rear of the queue and the existing elements are deleted from other end called the front of the queue. The figure a) below illustrates a queue containing three elements A, B, and C.

A Figure: Queue front a)

C rear b)

B front

C rear

B front c)

E rear

A is at the front of the queue and C is at the rear. In figure b), an element has been deleted from the queue. Since elements may be deleted only from the front of the queue, A is removed and B is now at the front. In figure c), when items D and E are inserted, they must be inserted at the rear of the queue. Since D was inserted before E, it will be removed earlier. The first element inserted into a queue is the first element to be removed. For this reason a queue is sometimes called FIFO (First-In, First-Out) list as opposed to a stack, which is a LIFO. Examples in real world are: A line at a bank or at a bus stop, line at the ticket counter etc. Operation in Queue The two basic operations that can be applied to the queue are: a) Enqueue

70

b) Dequeue Enqueue The enqueue operation is also called the insertion operation. With the help of this operation we insert the item at the rear of the queue. After every enqueue operation the rear of the queue is increased by 1. The result of an illegal attempt to insert an element in the queue which is full is called queue overflow. Dequeue The dequeue operation is also called as deletion/remove operation. With the help of this operation we remove or delete the item at the front of the queue. The dequeue operation can be applied only if the queue is not empty; there is no way to remove an element from a queue containing no elements. The result of an illegal attempt to remove an element from an empty queue is called queue underflow. Algorithm for Enqueue Operation 1. Declare an array large enough to hold the elements of the queue 2. Declare two pointers front and rear and initialize them as front = 0 and rear = -1 3. Check whether the Queue is full 4. If the Queue is full print the Queue overflow message and terminate the program 5. If the Queue is not full, increment the value of rear by 1 6. Insert the data at the rear of the queue 7. Exit. Syntatically Let queue[maxsize] is an array for implementing the queue i. Check for queue overflow if rear=maxsize-1, then print queue overflow message and exit ii. Set rear=rear+1 i.e. increase rear by 1 iii. Set queue[rear]=data i.e. insert data in new rear position iv. Exit. Algorithm for Dequeue operation 1. Check whether the queue is empty 2. If the queue is empty print the queue underflow message and terminate the program 3. If the queue is not empty remove the element from the front of the queue 4. Increase the value of front by 1 5. Exit Syntatically i. Check for the queue underflow if rear<front then print "QUEUE IS EMPTY" and exit else remove the element from the front of the queue ii. Increment the front set front=front-1 iii. Exit. Source Code #include<iostream.h> #include<conio.h> #include<process.h> # define maxsize 10 class queue { int front; int rear; int item[maxsize]; public: queue() { front=0; rear=-1; } void enqueue(int); void dequeue(); void display(); }; void queue::enqueue(int x) { if(rear==maxsize-1) { cout<<"Queue Overflow"<<endl; exit(0); }

71

else { rear++; item[rear]=x; } } void queue::dequeue() { int x; if(rear<front) { cout<<"Queue is empty"<<endl; exit(0); } else { x=item[front]; front=front+1; cout<<"Item deleted is "<<x<<endl; } } void queue::display() { cout<<"Queue content is:"<<endl; for(int i=front;i<=rear;i++) cout<<item[i]<<endl; } main() { queue q; q.enqueue(10); q.enqueue(20); q.enqueue(30); q.display(); q.dequeue(); q.dequeue(); q.display(); getch(); }

Module 10 STREAMS IN C++ A stream is a term defining a flow of data. Different streams are used to represent different kinds of data flow. For example, the iostream class represents the input output stream. Thus each file in c++ is an object of a particular stream class. In the same way in C++, creation and accessing of files from secondary storage devices is defined in side stream class. The I/O system of C++ contains a set of classes that define the file handling methods. These include ifstream, ofstream and fstream. These classes are derived from fstreambase and also include the corresponding header file <iostream.h>; FSTREAM.H takes care of all stream I/O. Class Ifstream Derived From istream, fstreambase Purpose Input from file/ Read a stream of object from a specified file

ofstream

ostream, fstreambase

Output to file / Write a stream of object from a specified file

Fstream

iostream, fstreambase

Both input and output / Both read and write a stream of objects on a specified fiel

istream, ostream, and iostream are derived from ios class. So, ifstream, ofstrea, fstream also have access to all operations defined by ios.

72

Opening a file This involves following steps:

1.
2.

Create a file stream object to manage the stream using the appropriate class. That is, the class ofstream is used to create the output stream and the class ifstream to create the input stream. Initialize the file object with the desired filename.

a) ifstream It is derived from the base class of istream and is used to read a stream of object from a file. For example, the following program segment shows how a file is opened to read a class of stream objects from a specified file. #include<fstream.h> #include<conio.h> main() { ifstream infile; //object created infile.open("c:\test.txt"); //opening a file to read ---------------------------------} b) ofstream it is derived from the base class of ostream and is used to write a stream of objects in the file. For example, the following program segment shows how a file is opened to write a class of stream objects on a specified file. #include<fstream.h> #include<conio.h> main() { ofstream outfile; //object created outfile.open("c:\test.txt"); //opening a file to write -----------------} c) fstream it is derived from the base class of iostream and is used for reading and writing a stream of objects in the file. The #include<fstream.h> automatically includes the header file iostream.h. For example, the following program segment shows how a file is opened for both reading and writing a class of stream objects on a specified file. #include<fstream.h> #include<conio.h> main() { fstream file; //object created file.open("c:\test.txt",ios::in||ios::out); //opening a file to write -----------------} The member function open( ) is used to open the file. It takes two arguments: first argument is the name of the file to be opened and second is the mode in which file has to be opened. File opening modes There are several modes in which a stream object can be opened. We can combine these bits specifies using logical OR operator. Each combination of mode bits specifies various aspects of how a stream object will be opened. Mode ios::in ios::out ios::ate ios::app ios::trunc ios::norcreate ios::noreplace ios::binary Result Open for reading (default for ifstream) Open for writing (default for ofstream) Start reading or writing at the end of file (AT End) Start writing at end of file (APPend) Truncate file to zero length if it exists (TRUNCate) Error when opening if file does not already exist Error when opening for output if file already exists, unless ate or app is set Open file in binary (not text) mode

For ifstream, default mode is ios::in, so no need to specify it. For ofstream, default mode is ios::out, so no need to specify it. For fstream, there is no default mode so mode has to be defined explicitly. If we want to preserve whatever was in the file we should use ios::app. In this case whatever we write to the file will be added at the end of the existing contents. If we want to perform both input and output on the file in binary mode we can use the following open command.

73

fstream file; file.open(filename, ios::in || ios::out || ios::binary); The vertical bars between the flags cause the bits representing these flags to be logically combined into a single integer, so that several flags can be applied simultaneously. Closing a file The member function close( ) is used to close a file, which has been opened, for file processing such as to read, to write, and for both read and write functions. The close( ) member function is called automatically by the destructor functions. However, one may call this member function to close the file explicitly, the close() member function will not take any arguments. The general syntax of the close() member function is: #include<fstream.h> #include<conio.h> main() { ofstream file; file.open("c:/test.txt"); --------------------------------------file.close(); getch(); } Complete example showing writing and reading operation #include<fstream.h> #include<conio.h> main() { char name[40]; int age; char address[40]; //Writing to file or Outputting to file using object of ofstream class ofstream f; f.open("c:/try.txt"); //By default file is opened in writing mode cout<<"Enter the data to send to file:"<<endl; cout<<"Enter name:"; cin>>name; cout<<"Enter age:"; cin>>age; cout<<"Enter Address:"; cin>>address; f<<"\t"<<name<<"\t"<<age<<"\t"<<address; f.close(); //Reading from file or inputting from file using object of ifstream class ifstream i; i.open("c:/try.txt"); //By default file is opened in reading mode cout<<"Contents of file...."<<endl; i>>name; i>>age; i>>address; cout<<name<<"\t"<<age<<"\t"<<address<<endl; getch(); } From above program only one record can be displayed at a time. For adding record at the end of existing file and to display all the records in the file, the above program is modified as: #include<fstream.h> #include<conio.h> main() { char name[40]; int age; char address[40]; //Writing to file or Outputting to file using object of ofstream class ofstream f; f.open("c:/try.txt",ios::app); //file is opened in append mode cout<<"Enter the data to send to file:"<<endl; cout<<"Enter name:";

74

cin>>name; cout<<"Enter age:"; cin>>age; cout<<"Enter Address:"; cin>>address; f<<"\t"<<name<<"\t"<<age<<"\t"<<address; f.close(); //Reading from file or inputting from file using object of ifstream class ifstream i; i.open("c:/try.txt"); cout<<"Contents of file...."<<endl; while(!i.eof()) //Reading occurs until the end of file is reached { i>>name; i>>age; i>>address; cout<<name<<"\t"<<age<<"\t"<<address<<endl; } getch(); } Writing to a file try.txt In above program, since the file is opened in append mode, each time you enter new data it will be inserted at the end of file. In place of ios::app if you use ios::out the old data will be replaced by new one. Reading from a file try.txt In above program, the file is opened in reading mode to perform input operation. Since default mode for ifstream is ios::in we are not using any mode explicitly. Here, we are using while(!i.eof()) which means file is read until the end of file is reached. If input statements were written without using while(!i.eof()) only the first data will be displayed. Stream state member functions In C++ file stream classes inherit a stream state member from ios class. The stream state member functions give the information status like end of file has been reached or file open failure and so on. Some of the commonly used stream state member functions are: a) eof() The eof() stream state member function is used to check whether a file pointer has reached the end of a file character or not. It returns nonzero (meaning TRUE) when there are no more data to be read from an input file stream, and zero (meaning FALSE) otherwise.The general syntax of the eof() stream state member function is: #include<fstream.h> #include<conio.h> main() { ifstream file; file.open("c:/test.txt"); while(!file.eof()) { --------------------------------------} file.close(); getch(); } b) fail() The fail() stream state member function is used to check whether a file has been opened for input or output successfully, or invalid operations are attempted or there is an unrecoverable error. If it fails, it returns a nonzero character. The general syntax of the fail() stream state member function is: #include<fstream.h> #include<conio.h> main() { fstream file; file.open("c:/test.txt",ios::in||ios::out); if(file.fail()) { cout<<"No such file exist ,could not open a file"<<endl; exit(1); } getch(); }

75

c) bad() The bad() stream state member function is used to check whether any invalid file operations has been attempted or there is an unrecoverable error. The bad() member function returns a non zero if it is true; otherwise returns 0. The general syntax of the bad() stream state member function is: #include<fstream.h> #include<conio.h> main() { fstream file; file.open("c:/test.txt",ios::in||ios::out); if(file.bad()) { cout<<"couldnot open a file"<<endl; exit(1); } } d) good( ) The good() stream state member function is used to check whether the previous file operations have been successful or not. The good() returns a non zero if all stream state bits are zero. The general syntax of the bad() stream state member function is: #include<fstream.h> #include<conio.h> main() { fstream file; file.open("c:/test.txt",ios::in||ios::out); if(!file.good()) { cout<<"couldnot open a file"<<endl; continue; ------------------------} } Some examples: A program to demonstrate the writing of a set of lines to a specified file myfile.txt #include<fstream.h> #include<conio.h> main() { ofstream file; file.open("c:/myfile.txt"); file<<"This is test"<<endl; file<<"Program to store a set of lines onto a file"<<endl; file.close(); getch(); } A program to demonstrate the writing of a set of lines to a specified file myfile.txt #include<fstream.h> #include<conio.h> main() { ofstream file; char fname[20],line[200]; cout<<"Enter the name of file to be opened:"<<endl; cin>>fname; file.open(fname); cout<<"enter the lines to store in the file:" cin>>line; cout<<"Your entered line will be stored in file"; file<<line; file.close(); getch(); }

76

A program to demonstrate copying content of one file to another. #include<fstream.h> #include<ctype.h> #include<stdlib.h> #include<conio.h> main() { ofstream outfile; ifstream infile; infile.open("c:/fname1.txt"); if(infile.fail()) { cout<<"No file exist for reading"<<endl; } outfile.open("c:/fname2.txt"); if(outfile.fail()) { cout<<"Unable to create a file for writing"; } cout<<"Now copying in progress........."; char ch; while(!infile.eof()) { ch=(char)infile.get(); //read single character from source file and store in ch ch=toupper(ch); // convert to uppercase outfile.put(ch); // write single character to a file } infile.close(); outfile.close(); getch(); } get( ) member function is used to read a single character from a file and put( ) member function is used to write a single character to a specified file.

Binary I/O The function write() and read(), unlike the functions put() and get(), handle the data in binary form. This means that the values are stored in the disk file in the same format in which they are stored in the internal memory. Binary format is more accurate for storing the numbers as they are stored in the exact internal representation. There are no conversions while saving the data and therefore saving is much faster. The binary input and output functions take the following form:

infile.read((char *)&v,sizeof(v)); outfile.write((char *) &v,sizeof(v));


These functions take two arguments. The first is the address of the variable v, and the second is the length of that variable in bytes. The address of the variable must be cast to type char* (i.e. pointer to the character type). We can use the binary input and output functions read() and write() for reading and writing class objects. Classes and File operations

I/O Operations on binary files (writing an object to disk) #include <fstream.h> #include<conio.h> class person { char name[40]; int age; public: void getdata( ) {

77

cout <<Enter name: ; cin >> name; cout << Enter age: ; cin>> age; } }; void main() { person p; p.getdata(); ofstream outfile(c:/person.dat,ios::binary); outfile.write((char*) &p, sizeof(p)); outfile.close(); getch(); } The getdata() member function of person is called to prompt the user for information, which it places in the p object. Heres some sample interaction: Enter name: Ram Enter age: 29 The contents of the p object are then written to disk, using the write() function. It takes two arguments: the address of the object to be written, and the length of the object in bytes. We use the sizeof operator to find the length of the p object. The address of the object must be cast to type pointer to char.

I/O Operations on binary files (reading an object back from disk) #include <fstream.h> #include<conio.h> class person { protected: char name[40]; int age; public: void showdata( ) { cout <<\nName: << name; cout << \nAge: << age; } }; main() { person p; ifstream infile(c:/person.dat,ios::binary); infile.read((char*) &p, sizeof(p)); p.showdata(); infile.close(); getch(); }

Following will be the output generated by the program Name: Ram Age: 29

78

Random access file processing File pointers and their manipulators Each file has two associated pointers known as the file pointers. One of them is called the input pointer (or get pointer) and other is called the output pointer (or put pointer). We can use these pointers to move through the files while reading or writing. When we open a file in read-only mode, the input pointer is automatically set at the beginning so that we can read the file from the start. Similarly, when we open a file write-only mode, the existing contents are deleted and the output pointer is set at the beginning.

Function for manipulation of file pointers seekg() Moves get pointer (input) to a specified location. seekp() Moves put pointer (output) to a specified location. tellg() Gives the current position of the get pointer. tellp() Gives the current position of the put pointer. For example, the statement infile.seek(10); Moves the file pointer to the byte number 10. Consider the following statements: ofstream fileout; fileout.open(abc.txt,ios::app); int p = fileout.tellp(); On execution of these statements, the output pointer is moved to the end of the file abc.txt and the value of p will represent the number of bytes in the file. Specifying offset Functions seek() and seekp() can also be used with two arguments as follows:

seekg(offset, refposition); seekp(offset, refposition);


The parameter offset represents the number of bytes the file pointer is to be moved from the location specified by the parameter refposition. The refposition takes one of the following three constants defined in the ios class: ios::beg ios::cur ios::end start of file current position of the pointer end of the file

Pointer offset calls Seek call Action fout.seekg(o,ios::beg); Go to the start fout.seekg(o,ios::cur); Stay at the current position fout.seekg(o,ios::end); Go to the end of the file fout.seekg(m,ios::beg); Move to (m+1)th byte in the file fout.seekg(m,ios::cur); Go forward by m bytes from the current position fout.seekg(-m,ios::cur); Go backward by m bytes from the current position fout.seekg(-m,ios::end); Go backward by m bytes from the end Each file object has associated with it two integer values called the get pointer and the put pointer. These are also called the current position and the current put position. These values specify the byte number in the file where writing or reading will take place. The seekg() and tellg() functions allow us to set and examine the get pointer, and the seekp() and tellp() functions perform these same actions on the put pointer. The seekg() function can be used in two ways. We can pass a single argument which represents the position. We can also use it with two arguments, where the first argument represents an offset from a particular location in the file, and second specifies the location from which the offset is measured. There are three possibilities for the second argument: beg is the beginning of the file, cur is the current pointer position, and end is the end of the file. A program to write and read on objects using random file access #include<fstream.h> #include<conio.h> #include<iostream.h>

79

class student { char name[40]; int age; char address[40]; public: void read() { cout<<"enter name:"; cin>>name; cout<<"enter age:"; cin>>age; cout<<"enter adress:"; cin>>address; } void display() { cout<<"Name:"<<name<<endl; cout<<"Age:"<<age<<endl; cout<<"Address:"<<address<<endl; } }; main() { student s[4]; ofstream outfile; ifstream infile; int endposition,position; int n; outfile.open("c:/test.txt",ios::app||ios::binary); for(int i=0;i<4;i++) { s[i].read(); outfile.write((char *)&s[i],sizeof(s[i])); } outfile.close(); infile.open("c:/test.txt",ios::in||ios::binary); infile.seekg(0,ios::end); //Move pointer to the end of file endposition=infile.tellg(); //Store the endposition n=endposition/sizeof(student); //total byte occupied divided by size // of one record gives the no of records cout<<"The number of records in the file are:"<<n<<endl; cout<<"Enter the record number to view:"; cin>>n; position=(n-1)*sizeof(s); //calculate the position of required record infile.seekg(position); // position the pointer in desired location infile.read((char *)&s[n],sizeof(s[n])); //Read desired record s[n].display(); //Display record from primary memory using display() member function infile.close(); getch(); }

80

Você também pode gostar