c++_mat - must go through

92
C++ Programming 1 C++ Programming Training Department Geometric Limited Class – Book

Upload: divya-thakur

Post on 25-Apr-2017

230 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: C++_Mat - Must Go through

C++ Programming

1

C++ Programming

Training Department Geometric Limited

Class – Book

Page 2: C++_Mat - Must Go through

C++ Programming

2

Table of Contents

Table of Contents______________________________________________________ 2

1. Introduction________________________________________________________ 5

Problems with Structured Programming __________________________ 5

The Object Oriented Approach ___________________________________ 5 Encapsulation ___________________________________________________________________ 6 Polymorphism ___________________________________________________________________ 6 Inheritance ______________________________________________________________________ 6

Features of C++ _________________________________________________ 7

C++ I/O library _________________________________________________ 8 Cascading << and >>_____________________________________________________________ 8

Scope resolution operator _______________________________________ 9

Manipulators ____________________________________________________ 9 The endl Manipulator _____________________________________________________________ 9 The setw Manipulator_____________________________________________________________ 9 The flush Manipulator_____________________________________________________________ 9 The dec, oct & hex manipulators ___________________________________________________ 9

Enumerated Data types _________________________________________ 10

2. Reference Variables _______________________________________________ 11

3. Dynamic Memory Allocation ________________________________________ 14

Memory Allocation in C++_______________________________________ 14

C++ Keyword new ______________________________________________ 14

C++ Keyword delete ____________________________________________ 15

4. Functions ________________________________________________________ 17

Inline Functions ________________________________________________ 17

Default Arguments _____________________________________________ 18

Function Overloading___________________________________________ 19

5. Exception Handling ________________________________________________ 21

How to handle an exception ? ___________________________________ 21

How to throw an exception ______________________________________ 22

How to catch an exception ______________________________________ 22

Using multiple throw and catch statements ______________________ 24

6. Classes __________________________________________________________ 26

Inline Class member function ___________________________________ 28

Page 3: C++_Mat - Must Go through

C++ Programming

3

Categories of class member functions _____________________________________________ 29

Classes, Objects and Memory ___________________________________ 29

The this Pointer ________________________________________________ 29

Function Chaining______________________________________________ 30

Static data members____________________________________________ 31 Static member functions _________________________________________________________ 32

The Constant Member Function _________________________________ 33

Structures and Classes _________________________________________ 34

7. Constructor & Destructor Functions __________________________________ 35

Constructors___________________________________________________ 35 Rules for Constructors : __________________________________________________________ 35 When the Constructor is called :___________________________________________________ 35 The default constructor __________________________________________________________ 36 How to create a temporary instance _______________________________________________ 36 Base member initialization________________________________________________________ 36

Copy Constructor ______________________________________________ 38

Destructors ____________________________________________________ 39 Rules for Destructors ____________________________________________________________ 40 When a destructor function is called _______________________________________________ 40

8. Friend Functions __________________________________________________ 41

Granting friendship to a function ________________________________ 41

Granting friendship to another class_____________________________ 42

9. Operator Overloading ______________________________________________ 45

Rules for Overloading an Operator ______________________________ 45

Unary Operator Overloading –Through Member function __________ 45

Unary Operator Overloading- Through Friend function ____________ 47

Overloading Increment/Decrement Unary Operators ______________ 48

Binary Operator Overloading - Through Member Function_________ 49

Binary Operator Overloading -Through friend Function ___________ 50

Overloaded Subscript Operator _________________________________ 51

10. Inheritance _______________________________________________________ 53

Defining a derived class ________________________________________ 53

Visibility Mode _________________________________________________ 54 Private derivation _______________________________________________________________ 54 Public derivation ________________________________________________________________ 56 Protected Access Rights _________________________________________________________ 57 Protected derivation _____________________________________________________________ 57

Page 4: C++_Mat - Must Go through

C++ Programming

4

Visibility of inherited members ____________________________________________________ 58

Overriding Member functions ___________________________________ 58

Constructor and Destructor functions with derived classes _______ 59

Multilevel Inheritance ___________________________________________ 61

Multiple Inheritance ____________________________________________ 63

Hybrid Inheritance______________________________________________ 64

Virtual Base Class______________________________________________ 64

Ambiguities in Multiple Inheritance ______________________________ 65

11. Polymorphism ____________________________________________________ 66

Virtual functions _______________________________________________ 68 Rules – Virtual functions _________________________________________________________ 69

Virtual destructor functions _____________________________________ 69

Abstract base classes __________________________________________ 71

How virtual functions work______________________________________ 72

12. Templates ________________________________________________________ 73

Function Templates ____________________________________________ 73

How to write a function template ?_______________________________ 74

Overloading a function template_________________________________ 75

Class Templates _______________________________________________ 76

13. Input Output in C++________________________________________________ 80

Formatted I/O __________________________________________________ 81

File I/O_________________________________________________________ 83

14. Miscellaneous ____________________________________________________ 87

Namespaces ___________________________________________________ 87

New Casting Operators _________________________________________ 88

RTTI – Run Time Type Information/Identification__________________ 89

The string Class________________________________________________ 90

Introduction to STL – Standard Template Library _________________ 91

Page 5: C++_Mat - Must Go through

C++ Programming

5

1. Introduction

Bjarne Stroustrup of AT&T Bell Laboratories developed C++ in the early 1980's in Murray Hill, New Jersey. He created C++ while adding features to C to support efficient event-driven simulation programs. His inspiration came from the language Simula67, which supported the concept of a class. AT&T made many improvements to this initial language before releasing it commercially for the first time in 1985. Since then C++ has continued to evolve with AT&T controlling the releases. Problems with Structured Programming As programs grow larger and complex, the structured programming approach fails. Analyzing the reasons for these failures reveals that there are weaknesses in the procedural paradigm itself. No matter how well the structured programming approach is implemented, large programs become excessively complex. In a procedural language, the emphasis is on doing things – read the keyboard, check for errors and so on. i.e. emphasis is on action. Data is given a second-class treatment. In procedural languages, we declare global variables; these variables can be accessed by all functions. These functions can perform various operations on the data. You may declare local variables, but they cannot be accessed by all functions. Now suppose a new programmer is hired to write a function to analyze the data in a certain way. Unfamiliar with the program, the programmer may create a function that accidentally corrupts the data. This is possible because the function has complete access to the data. Another problem is that since many functions access the same data, the way the data is stored becomes critical. The arrangement of the data cannot be changed without modifying all the functions that access it. What is needed is a way to restrict access to the data, to hide it from all but a few critical functions. This will protect the data and simplify maintenance. Procedural programs are often difficult to design. The problem is that their chief components - functions and data structures – do not model the real world very well. With traditional languages, there is a problem of creating new data types. You cannot bundle both X and Y into a single variable called Point and then add and subtract values. The Object Oriented Approach

The fundamental idea behind object-oriented languages is to combine into a single unit both data and the functions that operate on that data. Such a unit is called an object. An object’s functions, called member functions (methods), typically provide the only way to access its data. If you want to read a data item in an object, you call a member function in the object. It will read the item and return the value to you. You cannot access the data directly. The data is hidden, so it is safe from accidental alterations. Data and its functions are said to be encapsulated into a single entity.

Page 6: C++_Mat - Must Go through

C++ Programming

6

If you want to modify the data in an object, you know exactly what functions interact with it; the member functions in the object. No other functions can access the data. This simplifies writing, debugging and maintaining the program. All object-oriented programming languages have three traits in common: encapsulation, polymorphism and inheritance. Encapsulation Encapsulation is a mechanism that binds together code and data, and that keeps both safe from outside interference or misuse. Further, it allows the creation of an object. An object is a logical entity that encapsulates both data and the code that manipulates that data. When you define an object, you are implicitly creating a new data type. Polymorphism In literal sense, polymorphism means the quality of having more than one form. In the context of OOP, polymorphism refers to the fact that a single operation can have different behavior in different objects. In other words, different objects react differently to the same message. Object-Oriented programming languages support polymorphism, which is characterized by the phase “one interface, multiple methods”. Polymorphism is the attribute that allows one interface to be used with a general class of actions. Polymorphism helps reduce complexity by allowing the same interface to be used to specify a general class of actions. It is the compilers job to select the specific action (method) as it applies to each situation. Inheritance Inheritance is a process by which one object can acquire the properties of another object. This feature allows you to add refinements of your own to an existing object. Abstraction This is the ability to represent a complex problem in simple terms. In the object oriented approach it is seen in the ability to create a high-level class definition that has little or no detail included in it. We are able to “abstract” the problem to a simple class definition and only add detail later in the process. Specialization Seen in class structures, specialization is the ability to make lower level subclasses more detailed than their parent classes. Technically, specialization is defined as the ability of an object to inherit operations and attributes from a superclass (parent class) with possible restrictions and additions. These above two concepts work in conjunction with one and other. Abstraction allows us to define high-level classes that lack minute details of implementation while specialization supports the introduction of those details later in the class design. Reuse In object-oriented programming we have new tools that allow for an even better level of reusability. By taking advantage of things like polymorphism and inheritance we can create class definitions that are truly universal in their applicability.

Page 7: C++_Mat - Must Go through

C++ Programming

7

Features of C++

• Strictly enforces prototypes main( ) { // will give compilation error } // as main( ) is not prototyped

• Data declarations

Variable can be declared anywhere in the program for(int iCounter=0 ; iCounter <10 ; iCounter ++) { }

• Structures can have functions within them.

• Keyword struct need not be used while declaring structure variables It is treated as a User-Defined Data Type struct rec {

int iData ; } ; rec emprec ;

The same applies to enums.

• Block variable visibility

You cannot access variables defined within a block outside the block; it is only visible within the braces.

void main( ) { for(int iCounter =1 ; iCounter < 10 ; iCounter ++) { cout << iCounter ; int cube = iCounter * iCounter * iCounter ; cout << cube ; } }

Here variable cube is accessible only within the for loop whereas variable iCounter is accessible from the point of declaration onwards.

Page 8: C++_Mat - Must Go through

C++ Programming

8

C++ I/O library

Example 1.1 C++ I/O

The identifiers cin and cout are actually objects. They are predefined to correspond to the standard input and output streams respectively. A stream is an abstraction that refers to the flow of data.

The operator << is called the insertion or put to operator. It directs the contents of the variable on its right to the object on its left. It is the overloaded left-shift operator. (Chapter 9 explains the concept of operator overloading.)

The operator >> is called the extraction or get from operator. It directs the contents of the object on its left to the variable on its right. It is the overloaded right-shift operator. The statements beginning with # are called preprocessor directives. The header file iostream.h contains declarations that are needed by the cout identifier and the << operator. Without these declarations, the compiler will not recognize cout.

Cascading << and >> The << and >> operators can be cascaded to display or accept multiple values in the same statement.

E.g. cin >> iData >> chName ; cout >> “Value of iDate is : ” << iData << “Value of chName is : “ chName ;

Accepting a sentence.

cin.get(string,length) E.g. char str[10] ;

#include <iostream.h>

void main(void)

{

int iCounter = 10 ;

char chName[10] ;

cout << “Integer : “ << iCounter ;

cin >> chName ;

cout << “String : “ << chName ;

}

Page 9: C++_Mat - Must Go through

C++ Programming

9

cin.get(str,10) ;

Scope resolution operator Global variable can be accessed anywhere within the program using :: operator.

Example 1.2 Scope Resolution Operator In the example, :: iCounter, represents the global variable whereas m is the local variable. Manipulators Manipulators are operators used with the insertion operator << to modify – or manipulate – the way data is displayed. The header file for manipulators is iomanip.h.

The endl Manipulator

The endl manipulator sends a new line to the stream and also flushes the output buffer. cout << “Area is” << fArea << endl ;

The setw Manipulator

Specifies the width of the value to be printed. cout << setw(5) << iCounter ;

The flush Manipulator

The flush manipulator flushes the buffer.

cout << “Enter a num :” << flush ;

The dec, oct & hex manipulators

int iCounter = 10 ;

main( )

{

int iCounter = 5 ;

cout >> :: iCounter >> iCounter;

}

Page 10: C++_Mat - Must Go through

C++ Programming

10

The dec, oct and hex manipulators are used for decimal, octal and hexadecimal values. These manipulators set the stream state either to decimal, octal or hexadecimal. These manipulators work for both input and output streams.

Example 1.3 Manipulators

If you enter number ff, you get output as

The hex no is ff The octal no is 377

Enumerated Data types Enumerated Data types allow you to define your own data types. They simplify and clarify the program. Enums provide an elegant way of defining symbolic constants.

E.g. enum days_of_week {Sun,Mon,Tue,Wed,Thu,Fri,Sat} ; days_of_week d1,d2 ;

d1 = Mon ; d2 = Thu ;

int diff = d2 – d1 ; E.g. enum boolean {False,True} ;

#include <iostream.h>

#include <iomanip.h>

void main( )

{

cout << “Input a hex number “ ;

int iNum ;

cin >> hex >> iNum ;

cout << The hex no is “ << hex << iNum << endl ;

cout << The octal no is “ << oct << iNum << endl

;

}

Page 11: C++_Mat - Must Go through

C++ Programming

11

2. Reference Variables

A reference variable is new concept in C++ that provides the means by which an alias to another variable can be created. A reference provides an alias – a different name - for a variable.

A reference variable unlike a pointer variable does not have its own unique address. The primary advantage of passing by reference is that the function can access the actual variable in the calling program i.e. you don’t have to deference it. Among other benefits, this provides a mechanism for returning more than one value from the called function back to the calling function. Since the notation is cleaner, the user can focus on what the program does rather than how it is accomplished. Void references (void&) are not allowed.

E.g. int iNum ; int& iNumber = iNum ;

Since iNumber is just an alias for iNum, whenever number is referenced, iNum is really being used. Once a reference variable is initialized with some existing variable, it cannot be reassigned to some other variable as long as the reference variable remains in scope. If a reference variable is an alias for still another reference variable, then it really refers to the variable for which the first reference variable is an alias. i.e. the two reference variables are aliases for the same variable in the memory.

#include<iostream.h>

void intfrac(float,float&,float&) ;

int main( )

{

float fNum,fIntpart,fFacpart ;

do

{

cout << “Enter a real number : “ ;

cin >> fNum ;

intfrac(fNum,fIntpart,fFracpart) ;

Deleted: ¶¶

Page 12: C++_Mat - Must Go through

C++ Programming

12

Example 2.1 Reference Variables In the above example, fIntpart and fFracpart are passed by reference whereas num is passed by value. From the function call alone, there is no way to tell whether an argument will be passed by reference or by value. You may create constant reference variable. In this case, you may not modify the object for which the variable is an alias by using the variable. However, the object itself may still be changed.

E.g. int iNum ; const int& iNumber = iNum ; //Invalid ++iNumber ; //Valid ++iNum ;

You may not create a non-constant reference to a constant value because a reference sets up an lvalue, and this implies that somehow you are now able to change the constant. The only type of reference that you can create for a constant value is a constant reference.

//Invalid const int x = 0 ; int& ref_x = x ; //Valid const int y = 0 ; const int& ref_y = y ;

Following are some of the restrictions to references

• A reference must always be initialized

• Null references are prohibited

• You cannot have a reference to a reference

cout << “Integer part is :” << fIntpart

<< “Fraction part is :” << fFracpart << endl ;

} while(fNum != 0) ;

return 0;

}

void intfrac(float fN,float& fIntp,float& fFracp)

{

fIntp = float(long(fN)) ;

fFracp = fN - fIntp ;

}

Page 13: C++_Mat - Must Go through

C++ Programming

13

• You cannot create arrays of references

• You cannot have a pointer to a reference.

Page 14: C++_Mat - Must Go through

C++ Programming

14

3. Dynamic Memory Allocation

Memory Allocation in C++

In C++, there are basically three methods of allocating memory to store things- 1.Static Allocation 2.Stack Allocation 3.Heap Allocation

The Static Allocation is used for storing global variables and variables declared static (both local static variables and static class members). These variables have to persist for the entire run of a program—there is no point where they "go out of scope". Static space is permanently allocated and thus not available for anything else. The Stack Allocation is used for storing function parameters and non-static local variables. Depending on the processor or OS architecture, either the hardware or the application program maintains a stack, which is used for storing these things. When a function is invoked, it reserves enough space on the stack for its parameters and local variables. This space is reclaimed when the function terminates. The OS or the application has to set aside a fixed amount of space for the stack. Even though the stack can grow or shrink, potentially allowing the space to be used for some other purpose when the stack doesn’t need it, this isn’t done, because then you’d have to be careful to move things out of the way when the stack expanded, which is an unreasonable cost. But if the stack exceeds the amount of memory set aside for it (stack overflow), you’re just stuck and the program terminates.

Finally there’s Heap Allocation. The heap is all of the memory allocated to a program that isn’t being used to store the stack, the static variables, or executable code. Typically, this is most of the program’s address space. As a rule, C++ doesn’t automatically allocate anything on the heap. To put something on the heap, you ask the memory manager, a service provider of the OS, for a block of memory of a given size. The memory manager will then satisfy this request with memory from the heap. You ask for a block of memory with malloc ( ) in C or with the new operator in C++. In other words, the heap is the pool of memory that’s available to satisfy calls to malloc ( ).

You use the heap (the new operator) to store objects that you want to persist longer than a single function call but shorter than the whole program’s duration, and to store larger objects and more complex data structures. Unlike stack storage, heap storage isn’t automatically reclaimed; you have to do that by hand. If you forget, the heap will eventually fill up, leading to crashes or to severely compromised functionality. You allow storage to be reclaimed (and thus reused to satisfy a subsequent new) by calling free ( ) in C or using the delete operator (which usually calls free( )) in C++. Heap allocation is considerably slower than stack allocation, both because of the extra bookkeeping the memory manager must do, and often because of the extra bookkeeping the programmer must do. C++ Keyword new Like the malloc () function in C, the new operator in C++ is used to allocate contiguous, unnamed memory in the heap at execution time. Unlike malloc (), however the new operator no longer needs to use the sizeof keyword to specify the exact number of bytes needed. Instead you merely request the number of instances (or variables) of a particular type. The fact that different types occupy different amounts of storage is handled automatically by the compiler.

Page 15: C++_Mat - Must Go through

C++ Programming

15

If successful, the call to new will return a pointer to the space that is allocated else it will return NULL if the requested amount of space could not be found or some other error is detected. The difference between malloc and new is that while malloc always returns a pointer of type void*(hence we need to type cast it to appropriate type), new returns a pointer of the type of object being allocated. To get memory using new operator for a single instance of some primitive type: char* ptr_char = new char ; int* ptr_int = new int ; Primitive types allocated from the heap via new can be initialized with some user-specified value by enclosing the value within parentheses immediately after the type name. int* ptr_int = new int(65) ; To get memory for array of primitive type char* ptr_char = new char[20] ; // Array of 20 characters int* ptr_int = new int[10] ; // Array of 10 integers C++ Keyword delete The delete keyword is used to release the space that was reserved by new. It is analogous to the function free () in C, which takes as its argument a pointer to the space. To delete a single instance from the heap

int* ptr_int = new int ; delete ptr_int ; To delete an array of instances from the heap

int* ptr_int = new int[10] ; delete [ ] ptr_int ; To allocate and delete multidimensional arrays int rows = 3 ; const int cols = 5 ; int (*ptr) [cols] = new int [rows] [cols] ; delete [ ] ptr ; When allocating an array from the heap using new, the compiler must know all dimensions, except first. That is why the rows could be determined at execution time, but cols must be constant so that the compiler knows its value. To delete the array from the heap, the format of the delete statement is the same as that of a 1-dimensional array.

Page 16: C++_Mat - Must Go through

C++ Programming

16

Page 17: C++_Mat - Must Go through

C++ Programming

17

4. Functions Inline Functions Functions save memory space because all the calls to the function cause the same code to be executed; the function body need not be duplicated in the memory. When the compiler sees a function call, it generates a jump to the function. At the end of the function, it jumps back to the instruction following the call. While the sequence of events may save memory space, it takes some extra time (Recall the explanation of stack allocation, for every function call, a stack frame containing its local variables is pushed on to the stack!). There must be an instruction for the jump to the function, instruction for saving registers, instructions for pushing arguments into the stack in the calling program and removing them from the stack in the function, instructions for restoring registers and an instruction to return to the calling program. The return value (if any) must also be dealt with. All these instructions slow down the program. To save execution time in short functions you may elect to put the code in the function body directly in line with the code in the calling program. That is, each time there is a function call in the source file, the actual code from the function is inserted, instead of a jump to the function. An Inline function is written like a normal function in the source file but compiles into inline code instead of into a function. When the program is compiled, the function body is actually inserted into the program wherever the function call occurs.

Example 4.1 Inline Functions

#include <iostream.h>

inline float lbstokg(float pounds)

{

return 0.4535592 * pounds ;

}

void main( )

{

float lbs ;

cout << “Enter your weight in pounds “ ;

cin >> lbs ;

cout << “Your weight in Kilograms is : “ <<

lbstokg(lbs) ;

}

Page 18: C++_Mat - Must Go through

C++ Programming

18

Inline functions must be written before they are called. The inline keyword is actually a hint to the compiler. The compiler may ignore the inline and simply generate code for the function. Generally, the compiler ignores the inline keyword if the code contains a loop, static variable or there is a recursive call to the function. This also varies from compile to compiler. Default Arguments C++ allows you to call a function without specifying all its arguments. In such cases, the function assigns a default value to the arguments, which do not have matching arguments 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 possible default values. A function’s formal argument list now contains two types of formal arguments: mandatory and default. The order of these arguments must be as follows: the mandatory arguments, if present is written first, followed by any default arguments. A function may thus contain all mandatory arguments, all default arguments or a combination thereof. When the function is called, you must first specify all of the mandatory actual arguments, if present, in the order in which they are declared. Next, you may override the default arguments, if any, but only in the order in which they were declared.

Example 4.2 Default Arguments

Missing arguments must be the trailing arguments – those at the end of the argument list.

#include <iostream.h>

//The second argument defaults to the value 2

long power(int,int = 2) ;

void main( )

{ cout << “Enter the base “ ;

int base ;

cin >> base ;

//Using default value

cout << base << “squared is :” <<

power(base) ;

//Override default

cout << base << “cubed is :” <<

power(base,3) ;

}

long power(int base, int exp)

{

return (exp = = 0) ? 1L : base * power(base, exp – 1)

;

Page 19: C++_Mat - Must Go through

C++ Programming

19

Function Overloading One way C++ achieves polymorphism is using function overloading. In C++, two or more functions can share the same name as long as their arguments are different. In this situation, the functions that share the same name are said to be overloaded, and the process is referred to as function overloading. An overloaded function appears to perform different activities depending on the kind of data sent to it. Function overloading can occur only within a single scope. If two or more functions exist with the same name in the same scope, then the determination as to which function is actually called at runtime depends on the number and type(s) of the argument(s) that are supplied in the actual call of the function. Note that the variation in the argument list does not consider the return type of the overloaded functions. The return type may or may not be same. The compiler goes through a process known as “argument matching”, which involves an algorithm that matches the actual arguments in the function call against the argument list of all the functions with that same name. The compiler will then choose the function that best matches the actual argument(s) from among all of the functions by that name that are in scope and for which a set of conversions exists so that the function could possibly be called. To see why function overloading is important, first consider three functions found in the standard library of all C compilers: abs( ) , labs( ) , and fabs( ). The abs( ) function returns the absolute value of an integer, labs( ) returns the absolute value of a long, and fabs( ) returns the absolute value of a double. Although these functions perform almost identical actions, in C, three slightly different names must be used to represent these essentially similar tasks. This makes the situation more complex, conceptually, than it actually is. Although the underlying concept of each function is the same, the programmer has to remember three things, not just one. However, in C++ you can use just one name for all three functions as illustrated below.

#include <iostream.h>

// abs overloaded in 3 ways

int abs(int i) ;

double abs(double d) ;

long abs(long l) ;

void main( )

{

cout << abs(-10) << endl ;

cout << abs(-11.5) << endl ;

cout << abs(-9L) << endl ;

}

Page 20: C++_Mat - Must Go through

C++ Programming

20

Example 4.3 Function Overloading This program creates three similar but different functions called abs (), each of which returns the absolute value of its argument. The compiler knows which function to call in each situation because of the type of argument. The value of overloaded function is that they allow related sets of functions to be accessed with a common name.

int abs(int i)

{

cout << “using integer abs( ) “ << endl ;

return i < 0 ? –i : i ;

}

double abs(double d)

{

cout << “using double abs( ) “ << endl ;

return d < 0.0 ? –d : d ;

}

long abs(long l)

{

cout << “using long abs( ) “ << endl ;

return l < 0 ? –l : l ;

}

Page 21: C++_Mat - Must Go through

C++ Programming

21

5. Exception Handling

Exception handling allows you to manage run-time errors in an orderly fashion. Using C++, exception handling your program can automatically invoke an error – handling routine when an error occurs.

Exception refers to unusual condition in a program. They could be errors that cause the program to fail or certain conditions that could lead to error.

Without exception handling there are inherent problems in how a function can inform the caller that some error condition has occurred.

Example 5.1 Division by zero The preceding program works just fine unless the function divide( ) gets called with a divisor equal to zero. Exception handling solves this problem. How to handle an exception ?

• Find the problem (Hit the exception )

• Inform that an error has occurred (Throw the exception )

• Receive the error information (Catch the exception )

• Take corrective measures (Handle the exception )

#include<iostream.h>

double divide(long dividend, long divisor)

{

return (double) dividend / divisor ;

}

void main( )

{

cout << “Enter a dividend and a divisor : “ ;

long dividend, divisor ;

while( ! (cin >> dividend >> divisor) .eof( ))

{

cout <<dividend << ‘ / ’ << divisor<< ‘ = ’

<<divide( dividend, divisor)<< endl ;

cout << “Next dividend and divisor : “ ;

}

}

Page 22: C++_Mat - Must Go through

C++ Programming

22

How to throw an exception Exception handling solves the problem by providing a more elegant way to exit from the function, regardless of the function’s return type, and lets the caller retain control. Having the function throw, an exception does this. Syntax throw expression ;

Example 5.2 throw divisor

Example 5.3 throw message How to catch an exception In order for the calling routine to recognize the various types of exceptions that are being thrown, it must first invoke the function within the context of a try block or any function called within a try block. Syntax try { // call the function }

double divide(long dividend, long divisor)

{

if (divisor = = 0L)

throw divisor ;

return (double) dividend / divisor ;

}

double divide(long dividend, long divisor)

{

if (divisor = = 0L)

throw “Division by zero ” ;

return (double) dividend / divisor ;

}

Page 23: C++_Mat - Must Go through

C++ Programming

23

Even if there is only one statement that comprises the try block, the braces are still needed. Immediately following the try block you must write one or more exception handlers that can catch the exception being thrown.

Syntax Catch ( formal arguments ) { // process the exception } The exception handlers (also known as a catch block) can appear only after a try block or another exception handler. There can be no intervening statements. The process of throwing and catching an exception entails searching the exception handlers after the try block for the first one that can be invoked. After the handler has finished its processing, all remaining handlers are automatically skipped and execution of the program resumes normally with the first statement after the last handler.

#include<iostream.h>

double divide(long dividend, long divisor)

{

if ( divisor = = 0L )

throw “Division by zero “ ;

return (double) dividend / divisor ;

}

void main( )

{

cout << “Enter a dividend and a divisor : “ ;

long dividend, divisor ;

while( ! (cin >> dividend >> divisor) .eof( ))

{

try

{

cout << dividend << ‘ / ’ << divisor

<<‘=’<<divide( dividend, divisor);

}

Page 24: C++_Mat - Must Go through

C++ Programming

24

Example 5.4 Catch Using multiple throw and catch statements If a function can throw different types of exceptions then the catch block must handle these exceptions.

catch ( const char* message)

{

cerr << message << endl ;

}

cout << “Next dividend and divisor : “ ;

}

}

#include<iostream.h>

double divide(long dividend, long divisor)

{

if ( divisor = = 0L )

throw “Division by zero “ ;

else

{

if (divisor == 1L )

throw dividend ;

}

return (double) dividend / divisor ;

}

void main( )

{

cout << “Enter a dividend and a divisor : “ ;

long dividend, divisor ;

Page 25: C++_Mat - Must Go through

C++ Programming

25

Example 5.5 Multiple Catch

while( ! (cin >> dividend >> divisor) .eof( ))

{

try

{

cout<<dividend<<‘/’<<divisor<<‘=’

<<divide(dividend, divisor);

}

catch ( const char* message)

{

cerr << message << endl ;

}

catch ( float e )

{

cerr << e << endl ;

}

cout << “Next dividend & divisor : “ ;

}

}

Page 26: C++_Mat - Must Go through

C++ Programming

26

6. Classes A class allows you to define, associated pieces of data together with the functions to be used with that data and create a new type of data according to the needs of the problem to be solved. This new type is also called abstract data type or ADT.

A class allows data and functions to be hidden, if desired. A class definition consists of the class keyword, followed by the name of the class followed by a body, enclosed in braces, followed by semicolon. The class body contains variable definitions and function declarations. These variables and functions are intimately tied to the class and may only be used in association with an object belonging to that class. Although the variable definitions look like the ordinary definitions of local variables, no memory is allocated for them until a variable (object) of the class type is created. When this happens, all the memory for the variable is allocated at once.

The variables and functions (collectively called members) of a class are normally hidden from the outside world – the user cannot access them. These variables and functions are called private. The privacy can be made explicit using the keyword ‘private’; members in a class default to private. To allow the client programmer access to members, use the public keyword.

Syntax class <class name> {

private : //Data and member functions

public : //Data and member functions } ;

#include <iosteam.h>

class smallobj

{

private :

int somedata ;

public :

void setdata(int d)

{

somedata = d ;

}

Page 27: C++_Mat - Must Go through

C++ Programming

27

Example 6.1 Defining and instantiating Classes

An object is an instance of a class. Here we have two objects s1 and s2. A key feature of object-oriented programming is data hiding. It means that data is concealed within a class. Private data or functions can only be accessed from within the class. Public data or functions can be accessed from outside the class. Because setdata( ) is a member function of the smallobj class, it must always be called in connection with an object of this class. Therefore s1.setdata( ).

The member functions of the class can be written outside the class. This is done using the scope resolution operator, to specify that the function belong to a particular class.

void showdata( ) const

{

cout << “Data is “ << somedata ;

}

} ;

int main( )

{

smallobj s1,s2 ;

s1.setdata(1032) ;

s2.setdata(1784) ;

s1.showdata( ) ;

s2.showdata( ) ;

return 0;

}

Page 28: C++_Mat - Must Go through

C++ Programming

28

Example 6.2 Writing Methods outside the class.

Inline Class member function If you define a member function within the scope of the class definition, then the member function becomes automatically inline. The keyword inline does not need to be written. In the earlier example: In the first case since both setdata( ) and showdata( ) are written within the scope of the class definition, they would be inline functions, even though the keyword inline is not specified.

#include <iosteam.h>

class smallobj

{

public :

void setdata(int) ;

void showdata( ) const ;

private :

int somedata ;

} ;

void smallobj::setdata(int d)

{

somedata = d ;

}

void smallobj::showdata( ) const

{

cout << “Data is “ << somedata ;

}

int main( )

{

smallobj s1,s2 ;

s1.setdata(1032) ;

s2.setdata(1784) ;

s1.showdata( ) ;

s2.showdata( ) ;

return 0;

}

Page 29: C++_Mat - Must Go through

C++ Programming

29

Categories of class member functions The member functions of a class are designed to operate upon these data members, and can be categorized in three different ways:

• Manager Functions: These functions are used to perform “initialization” and “cleanup” of data members of the class. Constructors and Destructors discussed later on are examples of this category.

• Accessor Functions: These are constant functions that return information about an object’s current state. To ensure that these functions do not make any kind of modification to the data members, you add the keyword const after the formal argument list. In the earlier example the member function showdata( ) is an accessor function, hence the keyword const.

• Implementor Functions: These are the functions that make modifications to the data members. This is how the state of an object can be changed. These functions are also known as mutators. In the earlier example the member function setdata( ) is a mutator function.

Classes, Objects and Memory All the objects in a given class use the same member functions. The member functions are created and placed in the memory only once. The following diagram illustrates the same.

Fig. 5.1 Memory allocation for members The this Pointer When several instances of a class are created, each instance has its own separate copy of the member variables. But only one copy of each member function per class is stored in the memory and therefore is shared by all instances of that class.

Page 30: C++_Mat - Must Go through

C++ Programming

30

When a member function is called, the compiler must know which instance the member function is working on. For this reason, each nonstatic member function has access to a pointer variable that points to the instance being manipulated. This pointer variable is called the this pointer. The this pointer is passed automatically as an implicit argument to the member function when the function is called. In the earlier example when the member function setdata( ) is called for object s1 s1.setdata(1032) ; The this pointer is passed implicitly to the function. So in this case the this pointer has the address of s1. In the function, the statement somedata = d ; Here the data member somedata does not have any object or class qualification. This statement will now be qualified using the this pointer. this -> somedata = d ; Now it is clear that the data member somedata of object s1 is to be manipulated. The this pointer is implicitly declared. It can be used explicitly where you deem appropriate. The this pointer has absolutely no meaning outside the member function. Function Chaining Function chaining or function concatenation allows you to pass multiple messages to an object in the same statement. ie. You can call multiple member functions for a particular object in a single statement. instance.message1( ).message2( ).message( ) ; E.g. s1.setdata(1032).showdata( ) ; The “trick” is to make sure that each method that carries out a message returns the invoking instance (*this) by reference. This instance then may be used as the (implicit) invoking instance of the next function call without having to write it again explicitly. So the function setdata( ) in our example will need some changes to handle function chaining. The function will have to be rewritten as below:

smallobj& smallobj::setdata(int d) { somedata = d ; return *this ; }

The return type of the function setdata( ) is now smallobj&. When this is done a temporary reference variable of the type of the class is created that then becomes an alias to the invoking instance.

Page 31: C++_Mat - Must Go through

C++ Programming

31

Static data members In C++, you may declare static variables as data members.

• Static members are automatically initialized to zero. You may initialize them to some other value.

• Only one copy of the variable is created for multiple objects.

• Visible only within the class but life of static member is life of program.

• It is completely independent of any and all class instantiations.

• It is created and initialized before main( ). Static data members are instance-independent and are only declared within the scope of the class definition. The definition is done in the global part of the program after class definition. This is the case for all static members private, public and protected.

When writing the definition, you must not repeat the word static. However, you must repeat the type of the variable, followed by the class name, scope resolution operator and variable name. Initialization may be done here ; otherwise, it is initialized to zero.

Page 32: C++_Mat - Must Go through

C++ Programming

32

Example 5.3 Static data members

Static member functions

In C++, you may declare member functions as static.

• A static member function can have access to only static member variables

• While it is a member function, there is no this pointer.

• A static member function can be called using the class name, since it is instance-independent

class name :: function name

#include <iostream.h>

class item

{

public :

void getcount(int a)

{

number = a ;

count++ ;

}

void showcount( )

{

cout << count ;

}

private:

static int count ; //count is declared static

int number ;

} ;

int item::count ; //count is defined here ;

int main(void)

{

item it ;

it.getcount(5) ;

it.showcount( ) ;

return 0;

}

Page 33: C++_Mat - Must Go through

C++ Programming

33

Since C++ requires an instance of the class to invoke a nonstatic member function, and since static class members are instance-independent, if does not make sense to use the member function showcount( ) to display variable count in the earlier example. Therefore, we rewrite the example as follows:

Example 5.4 Static Member Function

The Constant Member Function The const member functions are basically the Accessor functions. They cannot modify the value of any data member (except for the mutable members). The keyword const must be present in the declaration as well as definition of the const member function.

#include <iostream.h>

class item

{

public :

void getcount(int a)

{ number = a ;

count++ ;

}

static void showcount(void)

{ cout << “Count : “ << count ;

}

private:

static int count ;

int number ;

};

int item::count ;

int main(void)

{ item it1,it2 ;

it1.getcount(10) ;

item :: showcount( ) ;

it2.getcount(20) ;

item :: showcount( ) ;

return 0;

}

Page 34: C++_Mat - Must Go through

C++ Programming

34

Example 5.5 Constant Function Constant functions may be used with constant objects as well. Let’s summarize the concept of const objects and cost member functions:

• If you do not want any member function to change the private data of your object then declare the object as a const object. You will have to initialize this object using a constructor. After that, the object will not change during the entire program execution.

• Set all mutator/implementor functions(functions changing the values of data members) as non-constant functions

• Set all accessor functions (functions which only inspect the values of data members) as const so that they do not accidentally change the values of data members.

• Non const functions will not be available to const objects.

• Constant functions will be available to const as well as non-const objects. Structures and Classes The only formal difference between class and struct is that in a class the members are private by default, while in a structure they are public by default.

class sample

{

public:

void show ( ) const ;

private:

int a ; mutable int b ; } ;

void sample :: show( ) const

{

cout<< a ;

cout << a++ ; // error. Show cannot change a

cout<< b++ ; // valid as b is mutable

}

Page 35: C++_Mat - Must Go through

C++ Programming

35

7. Constructor & Destructor Functions Constructors Constructors are non-static member functions that determine how the object of a class is created, initialized and copied. A constructor executes automatically when an object is created. Constructors are also invoked when local or temporary objects of a class are created. The constructor can be overloaded to accommodate many different forms of initializations for instances of the class. The execution of the constructor does not reserve memory for the instance itself. The compiler generates the code to do this, either in static memory, on the stack, or on the heap, after which control is handed over to the constructor to do the initialization of the data members. Rules for Constructors :

• Name of Constructors should be the same as name of the class to which it belongs.

• It is declared with no return type, not even void.

• It cannot be declared as static or const.

• It should have public or protected access.

• It can be overloaded. When the Constructor is called : An instance of some class comes into existence and causes the constructor function to be invoked when

• A global or static local variable of the class is defined (the constructor is called before main ()).

• An auto variable of the class is defined within a block and the location of its definition is reached.

• A temporary instance of the class needs to be created.

• An instance of the class is obtained from free memory via the new operator.

• An instance of some class is created that contains, as a data member, an instance of the class.

• An instance of some class derived from the class is created.

Page 36: C++_Mat - Must Go through

C++ Programming

36

Example 7.1 Constructors

The default constructor If you fail to write a constructor and destructor function, the compiler automatically supplies them for you. These functions have public access within the class and do nothing. The term default constructor refers to the constructor that takes no arguments, whether it is supplied automatically by the compiler or is written by you. The constructor that takes all default arguments may also serve as the default constructor. How to create a temporary instance It is possible to create a temporary instance of a class by writing the class name followed by parentheses, within which the constructor arguments, if any, are specified. If there are no arguments to be used in the constructor of the instance, the parentheses must still be written. The constructor function will then be called when the temporary instance is created. This can be done when you have individual data members of a class available, and need to combine them to form a new instance of the class. The following example has a function, which accepts the student number and name as arguments and returns a student object by creating a temporary instance. student makestd(int sno, char* nm) { return student(sno, nm) ; //Creates a temporary instance of student } Base member initialization Data members in a class can be initialized in a constructor function using the following syntax.

class student

{

public :

student( ) ;// Constructor with no arguments

student(int) ; // with one argument

student(int, const char*) ; // two arguments

private:int stdno ;

char* name ;

} ;

Page 37: C++_Mat - Must Go through

C++ Programming

37

Example 7.2 Base member initialization

The Const Data Members The constant data member for an object needs to be initialized in the constructor itself. This means that the value should be set in the initialization section of the constructor and not in the assignment section. Once set, its value cannot be changed in the further course of the program.

class employee

{

public :

employee( int cd, float s ,int i ) : code(cd), IQ(i)

{

salary = s ;

}

private :

const int IQ ;

int code ;

float sal ;

};

class employee

{

public :

employee( int cd, float s) : code (cd) , sal (s)

{ }

private : int code ;

float sal ;

} ;

Page 38: C++_Mat - Must Go through

C++ Programming

38

Example 7.3 Constant Data Member Copy Constructor The constructor to handle the creation and initialization of a class instance via an existing instance is called the copy constructor. Like the default constructor, if you do not write a copy constructor, then the compiler will automatically provide one for you. The default copy constructor performs member wise copy (also called as shallow copy) from the existing object to the new instance. This member wise copy is recursive in the sense that if a data member is also an instance of some other class, then all its data members are also copied. The general rule is that whenever there are pointer data members as part of the class definition, and then you must write your own copy constructor. When is the copy constructor is called?

• An instance of a class is created from an existing instance of the class.

• A function is called and an existing instance of the class is passed as an argument.

• An unnamed temporary variable is created to hold the return value of a function returning an instance of the class.

Page 39: C++_Mat - Must Go through

C++ Programming

39

Example 7.4 Copy Constructor The copy constructor may also be written as

integer(integer& i ) : code(i.code),sal(i.sal) { } Destructors A destructor is a function, which is called automatically whenever an instance of the class goes out of existence. The destructor is used to release space on the heap that the instance currently has reserved.

class integer

{

public :

integer(integer& i ) //Copy constructor

{

code = i.code ;

sal = i.sal ;

}

void showdata( )

{

cout << code << sal ;

}

private :

int code ;

float sal ;

} ;

int main(void)

{

integer s1(101,10000) ;

integer s2(s1) ; //Copy constructor invoked

s1.showdata( ) ;

s2.showdata( ) ;

return 0;

}

Page 40: C++_Mat - Must Go through

C++ Programming

40

Rules for Destructors

• Its name is the same as that of the class to which it belongs, except that the first character of the name must be a tilde(~).

• It is declared with no return type, not even void, since it cannot return a value.

• It cannot be declared static or const.

• It takes no input arguments, and so cannot be overloaded.

• It should have public access in the class declaration. When a destructor function is called The destructor function for a class is called:

• After the end of main( ) for all static, local to main( ), and global instances of the class.

• At the end of each block containing an auto variable of the class.

• At the end of each function containing an instance of the class as argument.

• To destroy any unnamed temporary instances of the class after their use.

• When an instance allocated on the heap is destroyed via delete.

• When an object containing an instance of the class is destroyed.

• When an object of a class derived from the class is destroyed.

Example 7.5 Constructor and Destructor

class sample

{

public :

sample(const char* nm) // Constructor

{

name = new char[strlen(nm) + 1] ;

strcpy(name,nm) ;

}

~sample( ) // Destructor

{

delete [ ] name ;

}

private :

char* name ;

} ;

Page 41: C++_Mat - Must Go through

C++ Programming

41

8. Friend Functions

Granting friendship to a function Because of encapsulation and data hiding, the only functions that have unrestricted access to a class’s private members are the member functions of that class. Any attempt by non-member functions to directly access these data members will result in compilation error.

However, in some cases you need non-member functions to access these data members. The easy way to do this would be to change the access category from private to public, but then this completely violates the concept of encapsulation and data hiding.

Declaring the function to be a friend of the class in which the data members are located can solve this dilemma. That is, the class in which the private members are located bestows friendship upon the function, not the other way around.

Because a friend function is always a non-member function of the class that bestows the friendship, it cannot be called via some instance of the class. Therefore there is no this pointer. The friend function is usually called with at least one argument consisting of an instance of the class, which bestowed the friendship.

Imagine that you want a function to operate on objects of two different classes. Perhaps the function will take objects of the two classes as arguments and operate on their private data.

#include <iostream.h>

class beta ; //Forward declaration

class alpha

{

public :

alpha( )

{

data = 3 ;

}

friend int frifunc(alpha , beta) ;

private :

int data ;

} ;

Page 42: C++_Mat - Must Go through

C++ Programming

42

Example 8.1 Friend Functions A class cannot be referred to until it has been declared. Class beta is referred to in the declaration of the function frifunc( ) in class alpha, so beta must be declared before alpha. This is called forward declaration. Note that, being a non-member function, a friend function can be declared under any access specifier in the class. Granting friendship to another class It is possible for one class to grant friendship to another class by writing the keyword friend followed by the class’s name. The keyword class is optional. When this is the case, the friend class has access to the private members defined within the other class i.e. all of the member functions of the friend class are friend functions of the class that bestows the friendship.

class beta

{

public :

beta( )

{

data = 7 ;

}

friend int frifunc(alpha , beta) ;

private :

int data ;

} ;

int frifunc(alpha a, beta b)

{

return(a.data + b.data) ;

}

int main( )

{

alpha aa ;

beta bb ;

cout << frifunc(aa,bb) ;

return 0;

}

Page 43: C++_Mat - Must Go through

C++ Programming

43

#include <iostream.h>

class list ;

class node

{

public :

node(int d=0) : data(d) ,next(0) { }

friend class list ;

private:

int data ;

node *next ;

} ;

class list

{

node *head ;

node *tail ;

public :

list( ) : head(0), tail(0) { } ;

~list( )

{

node *p=head ;

while ( p != 0)

{

node* temp = p->next ;

delete p ;

p = temp ;

}

}

list& add(int) ;

void print( ) ;

} ;

Page 44: C++_Mat - Must Go through

C++ Programming

44

Example 8.2 Linked List using Friend

When one class is a friend of another class, it only has access to the members within the other class. It does not inherit the other class. The members of the first class do not become members of the friend class i.e. friendship is unidirectional by default

list& list::add(int value)

{

node *n = new node(value) ;

if (!head)

head=n ;

else

tail->next=n ;

tail=n ;

return *this ;

}

void list ::print( )

{

for(node *p = head ;p != 0 ;p = p->next)

cout << p->data ;

}

int main(void)

{

list l ;

l.add(1).add(2).add(3) ;

l.print( ) ;

return 0;

}

Page 45: C++_Mat - Must Go through

C++ Programming

45

9. Operator Overloading

Whenever a new class is created, you need the ability to create new operators specifically designed to operate upon the data members of that class. This is possible by overloading the existing operators.

Although most of the existing operators have no inherent meaning in regard to any user-defined class, certain operators still work with any new class. For example the ‘&’ still yields the address of an instance of some class type, while the ‘=’ (by default) causes all data members of one instance of a class to be assigned to the corresponding data members of another instance of the same class. In addition, the direct member operator (dot) and sizeof operator are automatically valid.

Whatever meaning you give to the operator should make sense to someone reading your code. For example, obviously you should not overload the ‘+’ operator to mean any kind of subtraction. Rules for Overloading an Operator

• The only operators that can be overloaded are the ones from the C++ precedence chart.

• The pre-defined operator precedence rules cannot be rebuked. ie. you cannot for example make binary ‘+’ have higher precedence than binary ‘*’.

• No default arguments are allowed in overloaded operator functions.

• As with the per-defined operators, an overloaded operator may be unary or binary. If it normally is unary, then it cannot be defined to be binary. If it is normally binary, then it cannot be unary. However, if an operator can be both unary and binary, then it can be overloaded either way or both ways.

• The operator function for a class may be either a non-static member or global friend function.

• At least one of the arguments to the overloaded function (implicit or explicit) must be an instance of the class to which the operator belongs.

• These operator cannot be overloaded:

. direct member

.* direct pointer-to-member :: scope resolution ?: ternary

• These operators must be overloaded as member not friend functions :

= assignment ( ) function call [] subscript ���� indirect member operator

• These operators are normally overloaded as friend functions, not as members: << as a stream operator >> as a stream operator

Unary Operator Overloading –Through Member function

Page 46: C++_Mat - Must Go through

C++ Programming

46

Example 9.1 Unary Operator Overloading(Through member function)

Note that, while overloading a unary operator using as a member function, we do not send any argument to the operator function. This is because the function gets access to the calling object through its ‘this’ pointer.

#include <iostream.h>

class sample

{

public :

sample(int a = 0, int b = 0)

{

l = a ;

m = b ;

}

void display( )

{

cout << “l = “ << l << “m = “ << m ;

}

void operator – ( )

{

l = -l ;

m = -m ;

}

private: int l,m ;

} ;

int main( )

{

sample s1(10,20) ;

-s1 ; //calling overloaded operator function

s1.display( ) ;

return 0;

}

Page 47: C++_Mat - Must Go through

C++ Programming

47

Unary Operator Overloading- Through Friend function

Exampl

e 9.2:

Unary

Operator Overloading (Through friend function)

#include <iostream.h>

class sample

{

public :

sample(int a = 0, int b = 0)

{

l = a ;

m = b ;

}

void display( )

{

cout << “l = “ << l << “ m = “ << m ;

}

friend void operator – ( sample & );

private: int l,m ;

} ;

void operator – (sample & s)

{

s.l = -s.l;

s.m = -s.m;

}

int main( )

{

sample s1(10,20) ;

-s1 ; //calling overloaded operator function

s1.display( ) ;

return 0;

}

Page 48: C++_Mat - Must Go through

C++ Programming

48

As the friend function is a non-member function, the object needs to be explicitly passed to it. Note in the above program, the object s1 is passed by reference to the operator function. This is to ensure that the modifications done inside the function are applicable to the actual object.

Overloading Increment/Decrement Unary Operators To differentiate between the prefix and postfix versions of overloaded increment and

decrement operators, we need to make use of a pseudo argument. The following program demonstrates the overloaded increment operator using friend functions.

#include<iostream.h>

class sample

{

public:

int a ;

sample () : a(0)

{ }

sample(int x) : a(x)

{ }

sample friend operator ++(sample&);

//prefix version

sample friend operator ++(sample& , int );

//postfix version. int is a pseudo arg.

void showdata()

{

cout<<"\n A = "<<a<<endl;

}

};

sample operator ++(sample& s) //prefix

{

s.a=s.a+1; //the object is modified

return s; //and then returned

}

sample operator ++(sample& s, int ) //postfix

{

sample tmp=s; // original object saved as tmp

s.a=s.a+1; //object is modified

return tmp; //tmp is returned }

Page 49: C++_Mat - Must Go through

C++ Programming

49

Example 9.3: Overloading Increment Operator (Through friend function)

Binary Operator Overloading - Through Member Function

int main()

{

sample s1(10);

sample s2;

s2=++s1; //prefix version invoked

s2.showdata(); //Output : A = 11

s1.a=10;

sample s3;

s3=s1++; //postfix version invoked

s3.showdata(); //Output : A = 10

return 0;

}

#include <iostream.h>

class sample

{

public :

sample(int a = 0, int b = 0)

{

l = a ;

m = b ;

}

void display( )

{

cout << “l = “ << l << “ m =” << m ;

}

sample operator + (sample&) ;

private: int l, m ;

} ;

Page 50: C++_Mat - Must Go through

C++ Programming

50

Example 9.4 Binary Operator Overloading (Through Member Function)

In the example above, the + operator is overloaded to add objects of class sample. The operator overloading function name is written by using the keyword operator followed by the operator. The statement s3= s1 + s2 calls the overloaded operator function. Here object s1, being the invoking object, is passed implicitly to the function. So the ‘this’ pointer in the function is referring to the object s1. The second object, s2, is passed explicitly as a function parameter.

Thus, whenever a binary operator is overloaded as a member function, the operand on the left side of the operator is passed implicitly while the operator on the right must be passed explicitly. Binary Operator Overloading -Through friend Function

sample sample::operator + (sample& a)

{

sample temp ;

temp.l = l + a.l ;

temp.m = m + a.m ;

return temp ;

}

int main( )

{ sample s1(1,2), s2(3,6), s3 ;

s3 = s1 + s2 ; // call operator function

s3.display( ) ;

return 0;

}

#include <iostream.h>

class sample

{

int l,m ;

public :

sample(int a = 0, int b = 0)

{

l = a ;

m = b ;

}

Page 51: C++_Mat - Must Go through

C++ Programming

51

Example

9.5 Binary

Operator

Overloading (Through Friend Function)

Overloaded Subscript Operator Normally the subscript operator [], is overloaded in a pair of two versions: a non-const version and a const one. The const version of the subscript operator is called when the invoking object itself is a const object.

void display( )

{

cout << “l =” << l << “m =” << m ;

}

friend sample operator + (sample, sample ) ;

} ;

sample operator + (sample a , sample b)

{

sample temp ;

temp.l = a.l + b.l ;

temp.m = a.m + b.m ;

return temp ;

}

int main( )

{ sample a(1,2), b(3,6), c ;

c = a + b ;

c.display( ) ;

return 0;

}

Page 52: C++_Mat - Must Go through

C++ Programming

52

Example 9.6 Overloaded Subscript Operator

#include<iostream.h> class Array {

public: Array() //constructor { for ( int i = 0; i < Max_Size; ++i )

{ x[ i ] = i;

} }

int& operator[](const int a) //non-const version {

cout<< "nonconst" << endl; return x[ a ];

}

int operator[] ( const int a ) const //const version {

cout << "const" << endl; return x[ a ];

} private: enum { Max_Size = 10 }; int x[ Max_Size ]; //an array x is a data member

}; int main() { Array a;

int i = a[ 3 ]; //non-const a[ 5 ] = 55; //non-const

const Array ca; i = ca[ 3 ]; //const // ca[ 3 ] = 33; //compilation error cout <<a[3] << i <<a[5];

return 0; }

Page 53: C++_Mat - Must Go through

C++ Programming

53

10. Inheritance

Inheritance is the process of creating new classes called derived classes from base classes. The derived class inherits all the capabilities of the base class, but can also add refinements of its own. The base class is unchanged by this process.

Inheritance allows you to collect related classes into a hierarchy with the classes at the top serving as abstractions for those below. This implies that the derived class is a specialization of its parent class. In other words, the derived class is a type of base class, but with more detail added.

Defining a derived class

class derived-class : visibility-mode base-class { // derived class members }

The visibility-mode specifies the privileges that the derived class has as far as access to members of its parent class are concerned.

#include <iostream.h> class counter { public : counter( ): count(0) { } counter(int c) : count( c ) { } int get_count( ) { return count ; } void set_count(int c) { count = c; } void operator ++ ( ) { count ++ ; } private: unsigned int count ; } ;

Page 54: C++_Mat - Must Go through

C++ Programming

54

Example 10.1 Derived Classes

In the example, the class countdn is derived, with visibility-mode as public from the base class counter. If not specified the visibility-mode is always private.

Visibility Mode

Visibility mode can be private, public or protected.

Private derivation If a new class is derived privately from its parent class, then

• The private members inherited from the base class are inaccessible to new member functions in the derived class.

• The public members inherited from the base class have private access privilege i.e. they are treated as though they were declared as new private members of the derived class, so that new members functions can access them. However, if another private derivation occurs from this derived class, then these members are inaccessible to new member functions.

class countdn : public counter

{

public :

countdn(int c):counter(c){}

void operator -- ( )

{

int count = get_count();

count-- ;

set_count(count);

}

} ;

int main( )

{

countdn c1(10) ;

cout << " c1 = " << c1.get_count( ) ;

c1 ++ ;

c1 ++ ;

cout << " c1 = " << c1.get_count( ) ;

c1 -- ;

cout << " c1 = " << c1.get_count( ) ;

return 0;

}

Page 55: C++_Mat - Must Go through

C++ Programming

55

Example 10.2 (a) Private Derivations

Example10.2 (b) Private Derivations

class Base

{

public :

int num ;

} ;

class Derived1 : private Base

{public :

void f ( )

{

// num is accessible as it is declared public in Base class

++ num ;

}

} ;

class Base

{

private :

int num ;

} ;

class Derived1 : private Base

{

public :

void f ( )

{

// private base members not accessible

++ num ; //compile time error

}

} ;

Page 56: C++_Mat - Must Go through

C++ Programming

56

Example 10.2 (c) Private Derivations

Public derivation Public derivations are much more common than private derivations. If a new class is derived publicly from its parent class, then

• The private members inherited from the base class are inaccessible to new member functions in the derived class.

• The public members inherited from the base class may be accessed by new member functions in the derived class and by instances of the derived class.

class Derived2 : private Derived1

{

public :

void g ( )

{

// num not accessible as derivation from Base to Derived1 was private

++ num ;

}

} ;

class Base

{

public: int num1;

private : int num ;

} ;

class Derived1 : public Base

{

public :

void f ( )

{

//private base members not accessible

++ num1 ; //accessible as num1 is declared public in Base

}

} ;

Page 57: C++_Mat - Must Go through

C++ Programming

57

Example 10.3 Public Derivations

Protected Access Rights Declaring the data members as private is much too restrictive because new member functions in the derived class need to gain access to it. This is possible by using an access specification called protected. The members of a class that have been defined as protected can be accessed from within the class and from the derived classes. However, as far as instance of the derived class are concerned, protected and private are one and the same, so direct access is not possible.

class sample

{ private : // Visible to member functions within the class. protected :

// Visible to member functions of its own class and derived classes. public : // Visible throughout the program.

} ; Protected derivation The only difference between a public and a protected derivation is how the public members of the parent class are inherited.

• The private members inherited from the base class are inaccessible to new member functions in the derived class.

class Derived2 : private Derived1

{

public :

void g ( )

{

// num1 is accessible as derivation from Base to Derived1 was public

++ num1 ;

}

} ;

Page 58: C++_Mat - Must Go through

C++ Programming

58

• The protected members inherited from the base class have protected access privilege.

• The public members inherited from the base class have protected access privilege. Visibility of inherited members

Derived Class Visibility Base Class Visibility

Private Protected Public

Private No Access No Access No Access Protected Private Protected Protected

Public Private Protected Public

Tab 10.1 Visibility of inherited members

Overriding Member functions You can use functions in a derived class that have the same name and same signature as those in the base class. You might want to do this so that calls in your program work in the same way for objects of both base and derived classes and to add more functionality. If an instance or member function of the derived class refers to a data member of the base class that has been overridden, the member from the derived class will be used by default. To refer to the member function of the base class that has been overridden in the derived class, the base class name and the scope resolution operator are required. i.e. base-classname::member-function-name.

class Base

{

public :

Base ( int n = 0) : num (n) { }

int get_number( ) const

{

return num ;

}

protected :

int num ;

} ;

Page 59: C++_Mat - Must Go through

C++ Programming

59

Example 10.4 Overriding Member functions The output is

2 0

Constructor and Destructor functions with derived classes The derived class instance always contains the data members inherited from the base class. Therefore whenever a derived class is instantiated, the data members from both; the base class as well as derived class must be initialized. This requires two constructors to be executed; one for base class and another for derived class. The compiler will take care of this automatically and call both constructors. As soon as the derived class constructor gets control and establishes its formal arguments, the base class constructor will be called immediately i.e. before the derived class initialization is done.

class Derived : public Base

{

public :

Derived (int n = 1) : num (n)

{ }

int get_number( ) const

{

return num + 1 ;

}

private: int num ;

} ;

int main( )

{

derived d ;

// Calls derived::get_number( )

cout << d.get_number( ) ;

// Calls base::get_number( ) cout << d.base::get_number( ) ;

return 0;

}

Page 60: C++_Mat - Must Go through

C++ Programming

60

If the constructor for the base class is specified, the compiler will invoke that constructor. If not it will attempt to invoke the default constructor (the one that can be called with no explicit arguments). The destructor functions will get called in reverse order i.e. derived class first and base class last.

Example 10.5 Constructors and Destructors with derived functions.

class counter { public : counter( ) : count(0) { } counter(int c) : count( c ) { } int get_count( ) { return count ; } counter operator ++ ( ) { count ++ ; return counter(count) ; } private: unsigned int count ; } ; class countdn : public counter { public : countdn( ) : counter( ) { } countdn( int c) : counter( c)

//calling base class constructor { }

counter operator -- ( )

{ count -- ; return counter(count) ; } } ; int main( )

{

countdn c1, c2(10) ;

return 0;

}

Page 61: C++_Mat - Must Go through

C++ Programming

61

The base class constructor and destructor functions are unique, because the derived class does not inherit them. Multilevel Inheritance The following diagram illustrates multilevel inheritance.

Fig. 10.1 Multilevel inheritance Class B is inherited publicly from class A and Class C is inherited from Class B publicly. This is called multilevel inheritance.

class A

class B : public A

class C : public B

class student

{

public :

void get_number(int a)

{

rno = a ;

}

void display_rno( )

{

cout << “Roll no : “ << rno ;

}

protected :

int rno ;

} ;

Page 62: C++_Mat - Must Go through

C++ Programming

62

Example 10.6 Multilevel inheritance

class exam : public student

{

public:

void get_mark(int a, int b)

{

mark1 = a ;

mark2 = b ;

}

void display_mark( )

{

cout << mark1 << mark2 ;

}

protected :

int mark1, mark2 ;

} ;

class result : public test

{

public :

void display( )

{

total = mark1 + mark2 ;

display_rno( ) ;

display_mark( ) ;

cout << “Total : “ << total ;

}

private :

int total ;

} ;

Page 63: C++_Mat - Must Go through

C++ Programming

63

Multiple Inheritance A class can be derived from more than one base class. This is called Multiple inheritance. Multiple inheritance implies that a derived class has more than one parent or base class.

Fig. 10.2 Multiple Inheritance

class X class Y

class Z :public X , public Y

class X

{

public :

void fun1( ) ;

private: int a ;

} ;

class Y

{

public :

void fun2( ) ;

private: int b ;

} ;

class Z : public X , private Y

{

public :

void fun3( int) ;

private: int c ;

} ;

Page 64: C++_Mat - Must Go through

C++ Programming

64

Example 10.7 Multiple Inheritance Hybrid Inheritance Hybrid inheritance is the combination of multiple and multilevel inheritance. The following example illustrates hybrid inheritance. Class B and Class C are inherited from Class A. Class D is inherited from Class B and Class C. The typical problem arises in this scenario is that the members of Class A are inherited twice in Class D i.e. via class B and class C. This creates an ambiguous situation. The problem is often referred to as ‘Dreaded Diamond’ problem

Fig. 10.3 Hybrid Inheritance

Virtual Base Class To overcome the dreaded diamond problem, the super most base class is made a virtual base class.

Fig. 10.4 Virtual Base Class.

class A

class B : virtual public A class C : virtual public A

class D : public B, public C

class A

class B : public A class C : public A

class D : public B, public C

void Z::fun3(int g)

{

c = g ;

fun1( ) ;

fun2( ) ;

}

Page 65: C++_Mat - Must Go through

C++ Programming

65

Only one copy of members of class A is now inherited by class D. Ambiguities in Multiple Inheritance Ambiguity in multiple inheritance will arise if you have a class, which is derived from two parent classes, both of which have function with a common name. In such cases, use the class name followed by the scope resolution operator while calling the function to resolve the ambiguity.

Example 10.8 Ambiguities in Multiple Inheritance

class A

{

public : void show( )

{

cout << “Class A” ;

}

} ;

class B

{

public :void show( )

{

cout << “Class B” ;

}

} ;

class C : public A, public B

{

} ;

int main( )

{

C objc ;

objc.show( ) // ambiguous – will not compile

objc.A::show( ) // ok

objc.B::show( ) //ok

return 0;

}

Page 66: C++_Mat - Must Go through

C++ Programming

66

11. Polymorphism

Literally the word polymorphism means ability to take multiple forms. (Poly – many , morphism – ability to take forms ). In C++, polymorphism can be achieved in two ways viz. static polymorphism and dynamic polymorphism.

Fig. 10.1 Polymorphism

Compile time polymorphism is implemented in C++ using overloaded functions and operators. The overloaded member functions are selected for invoking by matching arguments at compile time i.e. The code associated with a call is decided at the time of compilation itself. This is called static or early binding.

When you use a pointer of type base class, the only class members that you can reference are of the base class, even if the pointer points to the derived class object.

Polymorphism

Compile Time Polymorphism

Run Time Polymorphism

Function Overloading

Operator Overloading

Achieved thru Virtual Functions

#include<iostream.h>

class Base

{

public :

void show( )

{

cout << “Base : “ << endl ;

}

} ;

Page 67: C++_Mat - Must Go through

C++ Programming

67

Example 11.1 Base class pointers The output for the example is :

Base Base

class Derv1 : public Base

{

public :

void show( )

{

cout << “Derv 1 : “ << endl ;

}

} ;

class Derv2 : public Derv1

{

public :

void show( )

{

cout << “Derv 2 : “ << endl ;

}

} ;

int main( )

{

Derv1 dv1 ;

Derv2 dv2 ;

Base* ptr ;

ptr = &dv1 ;

ptr -> show( ) ;

ptr = &dv2 ;

ptr -> show( ) ;

return 0;

}

Page 68: C++_Mat - Must Go through

C++ Programming

68

In example 11.1, we are assigning an address of the derived class object to a pointer of base class. In C++, pointers to objects of the derived class are type compatible with pointers to objects of the base class.

The output shows that every time the function from the base class is executed. The compiler ignores the contents of the pointer ptr and chooses the member function that matches the type of the pointer. The reason is that the compiler only knows about the type of the pointer itself, and nothing about the object that the pointer will eventually point at during execution time. Therefore, the class member that is hard-coded is used to generate an offset address relative to the start of the base class. This is called early or static binding since the member that is referenced is bound to the type of the pointer being used.

The goal of object-oriented programming language is to send a message to whatever instance happens to be pointed at by the pointer, as opposed to the type of the pointer itself. This is important because you can control the content (address) of the pointer at execution time, whereas the type of the pointer variable itself cannot be changed once it is hard-coded. In this manner, the instance itself can figure out what to do with the message and thereby implement the concept of polymorphism.

Therefore, what is needed is a method to delay the choice of which member function (method) gets executed until execution time. Having such a method would imply that by using a single pointer and member function name, the same function call (method) can be sent to the instance that has its address stored in the pointer. If these instances implement the same function (method) differently, then different results can be obtained. Such a method is called “late or dynamic binding because the compiler no longer makes the decision as to which function will get called. Virtual functions

Virtual means existing in effect but not in reality. A virtual function is one that does not exist but nevertheless appears real to some parts of a program. C++ implements late binding by using virtual functions. If a function in a base class definition is declared to be virtual, and is declared exactly the same way, including the return type, in one or more derived classes, then all calls to that function using pointers or references of type base class will invoke the function that is specified by the object being pointed at, and not by the type of the pointer itself. The keyword virtual is written before the return type (if any) of the function in the base class definition. It cannot appear outside a class definition. It is optional when declaring the same function in a derived class. It is through the use of virtual functions that C++ achieves the object-oriented goal of polymorphism. Coming back to the earlier example, change the base class so that it is as follows

Example 11.2 Virtual functions Now the output is:

class Base

{

public :

virtual void show( )

{ cout << “Base : “ << endl ; }

} ;

Page 69: C++_Mat - Must Go through

C++ Programming

69

Derv 1 Derv 2

The output shows that functions of the derived class and not the base class are executed. So the same function call ptr -> show( ) executes different functions depending on the contents of pointer ptr rather than the type of the pointer.

Rules – Virtual functions

• The virtual functions cannot be static members.

• They are accessed using object pointers or references.

• A virtual function can be a friend of another class.

• A virtual function in a base class must be defined, even though it may not be used.

• The prototypes of virtual function in base and derived class should be the same. Otherwise, it is not treated as virtual function.

• Cannot have virtual constructors.

• A base pointer can point to any derived-type object. Pointer to derived class cannot access an object of base type.

Virtual destructor functions If instances are created at run time on the heap via the new operator, then their destructors are automatically called when you execute the delete statement to release the space occupied by the instance itself. Because a derived class instance always contains a base class instance, it is necessary to invoke the destructor of both classes in order to ensure that all of the space on the heap is released.

#include <iostream.h>

class base

{

public :

virtual void identify( )

{

cout << “Base class “ << endl ;

}

~base( )

{

cout << “Base destructor “ << endl ;

}

} ;

Page 70: C++_Mat - Must Go through

C++ Programming

70

Example 11.3 (a) Virtual destructor

The output is Derived class Base destructor

The destructor function of the derived class did not get called. The reason is that the pointer type was base, so the actual instance the pointer was pointing at became irrelevant in determining which destructor function would be called.

To correct this problem, you must make the destructor function in the base class virtual. This violates the rule that states that virtual functions must have the same name, because destructor functions cannot have the same name since their names are based on the class names. Nevertheless, the compiler takes this into account and simply ignores the name of the destructor.

class derived : public base

{

public :

virtual void identify( )

{

cout << “Derived class “ << endl ;

}

~derived( )

{

cout <<“Derived destructor”<< endl ;

}

} ;

#include <iostream.h>

class base

{

public :

virtual void identify( )

{

cout << “Base class “ << endl ;

}

Page 71: C++_Mat - Must Go through

C++ Programming

71

Example 11.3 (b) Virtual destructor

The output is Derived class Derived destructor Base destructor

Abstract base classes Abstract base classes are classes used only for deriving other classes i.e. no objects can be defined of base class. This class cannot be instantiated. (A class, which can be instantiated, is called as a concrete class.) The designer of abstract base classes, while allowing for derivations to occur via protected data members and virtual functions, wants to prevent the user from actually creating an instance of the base class.

virtual ~base( )

{

cout<<“Base destructor”<<endl ;

}

} ;

class derived : public base

{

public :

virtual void identify( )

{

cout << “Derived class”<<endl ; }

virtual ~derived( )

{

cout<<“Derived destructor”<< endl ;

}

} ;

int main( )

{

base* ptr_base = new derived ;

ptr_base -> identify( ) ;

// Calls function from derived class

delete ptr_base ;

return 0;

}

Page 72: C++_Mat - Must Go through

C++ Programming

72

To create an abstract base class, you must specify at least one pure virtual function. A pure virtual function is a virtual function with no body.

class Base

{ public : virtual void show( ) = 0 ; } ;

The equal sign here has nothing to do with assignment; the value 0 is not assigned to anything. The = 0 syntax is simply to tell the compiler that the function will be pure – i.e. have no body.

A destructor function, even though it can be virtual, can never be made into a pure virtual function. How virtual functions work Late binding requires some overhead but provides increased power and flexibility. First, the compiler creates a table called the virtual function table, usually referred to as the ‘vtbl’. This table contains the address of all of the virtual functions within the class. The first address occupies position 0, the next position 1, etc. For each derived class, the table is duplicated, and if a virtual function is redefined, then its address replaces the address of the corresponding function from the base class. Any new virtual functions are appended to the end of the table. Whenever an instance of a class is created, the compiler reserves some extra bytes for use as a pointer to the ‘vtbl’. This pointer is referred to as the ‘vptr’, or virtual pointer. It is automatically initialized to point to the ‘vtbl’ for the class to which it belongs. When you create a pointer of type base and store into it the address of a base or derived instance, and then execute a function using this pointer, the compiler will fetch the address pointed at by ‘vptr’ of the invoking instance (*this), offset this address by the index of the function in question (0 for first, 1 for next), fetch the address from the ‘vtbl’, and execute the function that this address points at.

Page 73: C++_Mat - Must Go through

C++ Programming

73

12. Templates With a template, it is possible to create generic functions and generic classes. In generic function or class, the type of data upon which the function or class operates is specified as a parameter. Thus, you can use one function or class with several different types of data without having to explicitly recode specific versions for different data types. Function Templates Though function overloading is very useful, there are inherent problems when writing functions that are similar in their behavior.

Example 12.1 Max using function overloading

The output is :

#include<iostream.h>

int max(int x, int y)

{

return (x > y) ? x : y ;

}

long max(long x, long y)

{

return (x > y) ? x : y ;

}

double max(double x, double y)

{

return (x > y) ? x : y ;

}

char max(char x, char y)

{

return (x > y) ? x : y ;

}

int main( )

{ cout << max(1, 2) << endl ;

cout << max(4L, 3L) << endl ;

cout << max(5.62, 3.48) << endl ;

cout << max(‘A’, ‘a’) << endl ;

return 0;

}

Page 74: C++_Mat - Must Go through

C++ Programming

74

2 4 5.62 a

Although function overloading has been used, the problem with this example is that there is still too much repetitious coding. Each function is doing essentially the same thing – returning the greater of its two input arguments. Now instead of your having to write many similar max( ) functions, it would be nice to be able to write just one max() function that returns the greater of its two input arguments and can accommodate almost any type of input argument.

A function template solves the problem by allowing you to write just one function that serves as a skeleton, or template, for a family of functions whose task are all similar. At the same time full type, checking is carried out.

This function template does not specify the actual types of arguments that the function accepts; instead, it uses a generic, or parameterized, type as a “place holder” until you determine the specific type. This choice occurs implicitly when you make a call to the function. At this time the compiler infers the type of actual arguments and then proceeds to instantiated the function with the actual type by replacing the generic type with the type you specify. For each new type that you code, a different function, called a template function, will be instantiated.

How to write a function template ? A function template should be written at the start of your program in the global area, or you may place it into a header file. All function templates start with a template declaration.

Example 12.2 Function Template

#include<iostream.h> template <class T> const T& max(const T& x, const T& y) { return (x > y) ? x : y ; } int main( ) { cout << max(1, 2) << endl ; cout << max(4L, 3L) << endl ; cout << max(5.62, 3.48) << endl ; cout << max(‘A’, ‘a’) << endl ; cout << max(5, 6) << endl ; return 0; }

Page 75: C++_Mat - Must Go through

C++ Programming

75

The output is :

2 4 5.62 a 6

Each of the first four max( ) function calls causes a template function to be instantiated, first with an int , then with a long, then with a double and then with a char. The last call using two integers does not cause another instantiation to occur because this call uses the instantiated function generated by the first call that also used integers. You cannot instantiated the function template with different types. The following call to the max( ) function will not compile because the first argument is an int and the second is a double. cout << max(4, 2.6) << endl ; Overloading a function template Sometimes a function template just cannot handle all of the possible instantiations that you might want to do. The program either will not compile or, if it does the wrong answers may be obtained. In this case, you must overload the function template by declaring the function and specifying fixed argument types, just as you would for any other overloaded function. Pointers are a good example of where you need to overload a function template.

Example 12.3 Function Template and Overloading

#include<iostream.h>

#include<string.h>

const char* max(const char* x, const char* y)

{ return strcmp(x, y) > 0 ? x : y ; }

template <class T>

const T& max(const T& x, const T& y)

{ return (x > y) ? x : y ; }

int main( )

{ cout << max(1, 2) << endl ;

cout << max(‘A’, ‘B’) << endl ;

cout << max(“A”, “B”) << endl ;

return 0;

}

Page 76: C++_Mat - Must Go through

C++ Programming

76

The output is : 2 B

B Class Templates A class template defines all algorithms used by that class, but the actual type of data being manipulated will be specified as a parameter when objects of that class are created. Syntax template <class T> class test { // data & functions } The name of the non-parameterized class and the parameterized class is not the same. In other words, whenever you need to write the class name, E.g. In front of the scope resolution operator, you must tell the compiler that you are referring to a template class, not a non-template class. You do this by writing the class name followed by the parameterized type name between angle brackets. Assuming that the parameterized type name is T, then whenever you need to refer to the parameterized class name test within or outside the class definition of test, you must write

Test <T> However, that is not done when you are writing a constructor or destructor function name because in this context the name test is being used as a function, not class name.

Page 77: C++_Mat - Must Go through

C++ Programming

77

#include<iostream.h>

template <class T>

class test

{

public :

test( ) : number( 0 ) // Default constructor

{ }

test( T n) : number( n )

// 1 argument constructor

{ }

test(const test<T>& t ):number( t.number )

// Copy constructor

{ }

~test( ) //destructor

{ }

test<T>& operator = ( const test<T>& t )

{

number = t.number ;

return *this ;

}

friend ostream& operator << (ostream& stream, const test<T>& t )

{

return stream << t.number ;

}

private:

T number ;

} ;

Page 78: C++_Mat - Must Go through

C++ Programming

78

Example 12.4 Class Template If the member functions ( and friend functions ) are defined outside the class definition, then all the class member functions are automatically template functions, the template declaration must be repeated for each function.

#include<iostream.h>

template <class T>

class test

{

public :

test( ) ;

test( T ) ;

test(const test<T>& ) ;

~test( ) ;

test<T>& operator = ( const test<T>& ) ;

friend ostream& operator << (ostream& stream, const test<T>& ) ;

private:

T number ;

} ;

template <class T>

test <T> :: test( ) : number( 0 ) { }

template <class T>

test <T> :: test( T n ) : number( n ) { }

template <class T>

test <T> :: test(const test<T>& t ):number( t.number ) { }

template <class T>

test <T> :: ~test( ) { }

Page 79: C++_Mat - Must Go through

C++ Programming

79

Example 12.5 Class Template with methods outside the class.

template <class T>

test <T>& test<T>::operator =(const test<T>& t )

{

number = t.number ;

return *this ;

}

template <class T>

ostream& operator<<(ostream& stream, const test<T>& t )

{

return stream << t.number ;

}

int main( )

{

test <int> t1(10) ;

cout << t1 << endl ;

test <long> t2 (123456789L) ;

cout << t2 << endl ;

return 0;

}

Page 80: C++_Mat - Must Go through

C++ Programming

80

13. Input Output in C++

The I/O system in C++ provides a device independent interface to work with a variety of devices. This interface, known as a stream- is a sequence of bytes. A program extracts the bytes from an input stream and inserts byte into an output stream.

Fig. 13.1 Data Streams

Fig. 13.1 I/O streams The following streams are predefined: cin - the standard source of input (often the keyboard) cout - the standard destination for output (often the terminal window) cerr - the standard destination for error messages (often the terminal window). Output through this stream is unit-buffered, which means that characters are flushed after each block of characters is sent. clog - like cerr, but its output is buffered. It would be inefficient to update a file on disc each time a character was added. The character is written into a buffer, and when enough characters are in the buffer to make updating worthwhile, the buffer is flushed and the file on disc is updated. C++ offers ways to control the behavior of buffers, but often the default is ok. The C++ I/O system contains a hierarchy of stream classes used for input and output operations. These classes are included in the header file ‘iostream.h’. Fig. 13.2 shows some of the classes in this hierarchy.

Input Device

Output Device

Program

Extraction from input stream

Insertion into output stream

Output Stream

Input Stream

Page 81: C++_Mat - Must Go through

C++ Programming

81

Fig. 13.2 I/O classes

The ios class is a virtual base class that contains basic facilities that are used by all other i/o classes. It also contains a pointer to a strembuf object. The istream class declares input functions such as get (), getline (), read () etc. It contains overloaded extraction operator >> for all the basic data types. The ostream class declares output functions put (), write (). It contains overloaded insertion operator for all the basic data types. cin is an object of istream class which represents standard input stream. cout is an object of ostream class, which represents the standard output stream. The streambuf provides an interface to physical devices through buffers. It acts as a base for filebuf class used by ios files. Formatted I/O In C++, there are 2 related but conceptually different ways to format data. One is by setting various format status flags defined inside the ios class or by calling ios member functions, and the other is by using special functions called stream manipulators that can be included as part of an I/O expression. We have already seen some of the manipulators in Chapter 1. Using ios Flags 1. skipws discard leading white-space characters when reading input cin >> setiosflags(ios::skipws) >> x; 2. left left-justify the display of the next item in the output stream cout << setiosflags(ios::left) << x;

ios

istream ostream

iostream

ifstream ofstream fstream

fstreambase

streambuf

filebuf

Page 82: C++_Mat - Must Go through

C++ Programming

82

3. dec,oct,hex display or read the next value in base 10,8,16 resp. cout << setiosflags(ios::dec) << x; cin >> setiosflags(ios::dec) >> x; 4. showbase show the base of the next numeric value(e.g., 1F as 0x1F) cout << setiosflags(ios::showbase) << x; 5. uppercase display the characters in the following value in uppercase cout << setiosflags(ios::uppercase) << x; 6. showpos precede the display of the next value with a '+' sign cout << setiosflags(ios::showpos) << x; 7. scientific show the following floating-point value in scientific notation cout << setiosflags(ios::scientific) << x; Using setf() member function of ios class main( ) { cout.setf(ios::hex); cout.setf(ios::showbase); // or cout.setf(ios::hex | ios::showbase); cout << 100; // displays 0x64 } Format flags can be cleared using the unsetf( ) member function of the ios class. This function will clear the designated flags and return the value of the flags prior to being reset, as a 'long' value: main( ) { cout.setf(ios::uppercase | ios::scientific); cout << 100.12; // displays 1.0012E+02 cout.unsetf(ios::uppercase); // clear the 'uppercase' flag cout << '\n' << 100.12; // displays 1.0012e+02 } Using parameterized stream manipulators 1. setw set the display width of the following value cout << setw(4) << x; 2. setiosflags set the flags in the ios class according to the parameters cout << setiosflags(ios::fixed | ios::showpoint); cin >> setiosflags(ios::ws | ios::dec); 3. setprecision set the display precision of the next value cout << setprecision(2); 4. setfill fill all white spaces with the character argument cout << setfill('a'); 5. resetiosflags turn off the flags specified in the parameter (input, output) cout << resetiosflags(ios::showpos | ios::showpoint); cin >> resetiosflags(ios::ws | ios::hex);

Page 83: C++_Mat - Must Go through

C++ Programming

83

6. setbase set the base specified in the parameter cout << setbase(16); Using parameterized member functions 1. width(x); cout.width(4); cout << setw(4); cin.width(4); cin >> setw(4); 2. precision(x); cout.precision(2); cout << setprecision(2); 3. fill('a'); cout.fill('a'); cout << setfill('a'); File I/O The I/o system of C++ uses ifstream, ofstream and fstream classes for file handling. To use them, include the header file fstream.h. The class ifstream handles file input (reading from files), and ofstream handles file output (writing to files). The constructor for both classes will actually open the file if you pass the name as an argument. As well, both classes have an open command (a_file.open()) and a close command (a_file.close()). It is generally a good idea to clean up after yourself and close files once you are finished. Filebuf is used to set the file buffers to read aned write. Before processing a file it needs to be opened in one or more modes listed below.

Mode Description

ios::app If FileName is a new file, data is written to it. If FileName already exists and contains data, then it is opened, the compiler goes to the end of the file and adds the new data to it.

ios::ate If FileName is a new file, data is written to it and subsequently added to the end of the file. If FileName already exists and contains data, then it is opened and data is written at the current position.

ios::in If FileName is a new file, then the operation fails. If FileName already exists, then it is opened and its content is made available for processing.

ios::out If FileName is a new file, then it gets created as an empty file. Once it gets created empty, you can write data to it. If FileName already exists, then it is opened, its content is destroyed, and the file becomes as new. Therefore you can create new data to write to it.

ios::trunc If FileName already exists, its content is destroyed and the file becomes as new

ios::nocreate If FileName is a new file, the operation fails because it cannot create a new file. If FileName already exists, then it is opened and its content is made available for processing

ios::noreplace If FileName is a new file, then it gets created fine. If FileName already exists and you try to open it, this operation would fail because it cannot create a file of the same name in the same location.

Table 12.1 File Opening Modes

To open a file we must create a file stream and then link it to the filename. The file stream can be defined using the classes ifstream, ofstream and fstream depending upon the purpose i.e. whether we want to read data from file or write data to it or both. A file can be opened in 2 ways:

Page 84: C++_Mat - Must Go through

C++ Programming

84

• Using the constructor function of the class

• Using the member function open() of the class. Opening files using constructor This involves 2 steps:

• Create a file stream object to manage the streams using the appropriate class- ofstream to create the output stream, ifstream to create the input stream or fstream to create input-output stream.

• Initialize the file object with the desired filename. E.g. ofstream outfile(“samplefile”); //default mode is ios::out A file opened with ifstream object gets opened in ios::in mode while a file opened with ofstream object gets opened in ios::out mode by default. We can also mention the mode in the open () function. E.g.

ofstream a_file("test.txt", ios::nocreate); This will open the file test.txt for writing only if it exists. If the file does not exist already, a new file won’t be created. Opening files using open() We can use open function with previously created file stream object. E.g.

ifstream infile; infile.open(“samplefile”); //default mode is ios::in

Writing To a File

Page 85: C++_Mat - Must Go through

C++ Programming

85

Because C++ supports overloading operators, it is possible to use << and >> in front of the instance of the class as if it were cout or cin.

Example 13.1 Output to a File

#include <iostream.h>

#include <fstream.h>

int main()

{

char name[80];

int age;

ofstream outFile("junk.txt", ios::out);

// Check if there was an error opening file

if (!outFile)

{

cout << "Unable to open the file\n";

return 1;

}

cout << "Enter your name: ";

cin.getline( name);

cout <<”Enter your age :”;

cin >> age;

outFile << name << ”\t” << age << endl;

outFile.close(); // close file & release stream

return 0;

}

Page 86: C++_Mat - Must Go through

C++ Programming

86

Reading from a file

Example 13.2 Input from File Some Useful functions

• seekg() – puts the pointer at required location while reading from a file E.g.

File.seekg(-5,ios::end); will put the pointer 5 characters before end

File.seekg(ios::beg); will put the pointer to the beginning of the file.

File.seekg(10, ios::cur) will put the pointer 10 characters ahead from current position

• seekp() – is similar to seekg(), but it is used when you write in a file.

• tellg() – Returns an int type, that shows the current position of the inside-pointer. This works only when we read a file.

• tellp() – The same as tellg() but used when we write in a file

• Flush () - to save the data from the output buffer, even if the buffer is still not full

#include <fstream>

#include <iostream>

int main()

{

char FirstName[30], LastName[30];

int Age;

char FileName[20];

cout << "Enter the filename you want to open:

";

cin >> FileName;

ifstream Students(FileName);

// Check if there was an error opening the file

if (!Students)

{

cout << "Unable to open the file\n";

return 1;

}

Page 87: C++_Mat - Must Go through

C++ Programming

87

14. Miscellaneous The C++ language underwent many modifications since Bjarne Stroustrup first defined it. The standard, ANSI/ISO/IEC 14882:1998 which first became a standard in 1998, introduced many features to the language definition. Namespaces

Namespaces were introduced to the C++ language to prevent "namespace clashes". For example, suppose you wish to use some classes written by two software companies, and both of them produce a Math class. You want to use both of them, because each class has some useful function the other one doesn't provide. You get ready to compile the code, and the compiler complains that there are two Math classes and won't let you use both. This is one reason to use namespaces. It allows you to "qualify" each of the Math classes with a "namespace". So, if one company was called "SoftwareOne", they could create a namespace for their class, as:

namespace SoftwareOne { class Math { ... }; }

and if the other software company is called "SoftwareTwo", then they could create their namespace and write it as:

namespace SoftwareTwo { class Math { ... }; }

Each will create their own name space, and you may be able to create "Math" objects of each type.

int main() { SoftwareOne::Math x; // instance of SoftwareOne Math object SoftwareTwo::Math y; // instance of SoftwareTwo Math object }

Standard Library and namespace std The Standard Library is a fundamental part of the C++ Standard. The standard C++ library is a collection of functions, constants, classes and objects that extends the C++ language providing basic functionality to interact with the operating system and some standard classes, objects and algorithms that may be commonly needed. The standard library is defined under the namespace std.

Page 88: C++_Mat - Must Go through

C++ Programming

88

New-style Headers The headers under std namespace do not have the .h extension anymore e.g. iostream.h is now iostream. Some of the headers have got new names e.g. stdlib.h is now cstdlib and stdio.h is cstdio now.

#include <iostream> #include <cstdlib> : : int x; std::cin>>x; std::cout<< “You entered :” << x;

The using directive To avoid writing the namespace every time, you can use the directive ‘using’.

#include <iostream> using namespace std; : : int x; cin>>x; cout << “You entered :” <<x;

New Casting Operators The new standard has defined four casting operators: reinterpret_cast, static_cast, dynamic_cast and const_cast. All of them have the same format when used:

reinterpret_cast <new_type> (expression) dynamic_cast <new_type> (expression) static_cast <new_type> (expression) const_cast <new_type> (expression)

Where new_type is the destination type to which expression has to be casted.

• reinterpret_cast : casts a pointer to any other type of pointer. It also allows casting from a pointer to an integer type and vice versa.

class A { }; class B { }; A * a = new A; B * b = reinterpret_cast<B*>(a); // A* casted to B*

• static_cast : performs any casting that can be implicitly performed as well as the inverse cast (even if this is not allowed implicitly).

class Base { }; class Derived: public Base { }; Base * b = new Base; Derived * d = static_cast<Derived*>(b); // Base* casted to Derived* double d=3.14159265; int i = static_cast<int>(d); // double casted to int

Page 89: C++_Mat - Must Go through

C++ Programming

89

• dynamic_cast : is exclusively used with pointers and references to objects. It allows any typecasting that can be implicitly performed as well as the inverse one when used with polymorphic classes. However, unlike static_cast, dynamic_cast, it checks, if the operation is valid. That is to say, it checks if the casting is going to return a valid complete object of the requested type. Checking is performed during run-time execution. If the pointer being casted is not a pointer to a valid complete object of the requested type, the value returned is a NULL pointer.

class Base { virtual dummy(){}; }; class Derived : public Base { }; Base* b1 = new Derived; Base* b2 = new Base; Derived* d1 = dynamic_cast<Derived*>(b1); // succeeds Derived* d2 = dynamic_cast<Derived*>(b2); // fails: returns NULL

• const_cast :This type of casting manipulates the const attribute of the passed object, either to be set or removed:

class C { }; const C * a = new C; // a is pointer to Const C C * b = const_cast<C*> (a); // b is pointer to C, not to Const C

RTTI – Run Time Type Information/Identification Run-time type information (RTTI) is a mechanism that allows the type of an object to be determined during program execution. The 2 main C++ language elements to run-time type information are dynamic_cast and typeid operators.

• The dynamic_cast operator: Used for conversion of polymorphic types. class B { ... }; class D : public B { ... }; void f() { B* pb = new D; // base class pointer pointing to derived object B* pb2 = new B;

D* pd = dynamic_cast<D*>(pb); // ok: pb actually points to a D ... D* pd2 = dynamic_cast<D*>(pb2); // pb2 points to a B not a D // Cast was bad so pd2 == NULL ... }

• The typeid operator : Used for identifying the exact type of an object.

#include <iostream> #include <typeinfo.h> class Base { public:

Page 90: C++_Mat - Must Go through

C++ Programming

90

virtual void vvfunc() {} }; class Derived : public Base {};

using namespace std; int main() { Derived* pd = new Derived; Base* pb = pd; cout << typeid( pb ).name() << endl; //prints "class Base *" cout << typeid( *pb ).name() << endl; //prints "class Derived" cout << typeid( pd ).name() << endl; //prints "class Derived *" cout << typeid( *pd ).name() << endl; //prints "class Derived" delete pd; }

The string Class

The string class is a part of the standard library. It provides commonly needed facilities required for character string handling. It defines a number of member functions. Also a lot of non-member functions and operators work with objects of string class

#include <string>

using namespace std;

void main(void)

{

string str1 = "Hello";

string str2;

str2 = "World";

string str3 = str1 + " " + str2;

cout << str3 << endl;

string str11 = "abcdefghi";

string str12 = "0123";

str11.insert (3,str12);

cout << str11 << endl; // "abc0123defghi"

str12.insert (1,"XYZ");

cout << str12 << endl; // "0XYZ123"

string str13 = "abcdefghi";

str12.erase (5,3);

cout << str12 << endl; // "abcdei"

Page 91: C++_Mat - Must Go through

C++ Programming

91

Example 14.1: string class Introduction to STL – Standard Template Library The C++ STL (Standard Template Library) is a generic collection of class templates and algorithms that allow programmers to easily implement standard data structures like queues, lists, stacks, maps etc. The STL is implemented by means of the C++ template mechanism, hence its name. The STL is a generic library, meaning that its components are heavily parameterized: almost every component in the STL is a template. The 3 major components of STL are: Containers, Iterators, and Algorithms. Containers: Containers are objects that conceptually contain other objects. Containers are of 2 types: Sequence containers and Associative containers. Sequence containers hold elements of a single type as a linear sequence. That is, they are ordered in the same way as they are added to the container. The STL provides three sequence containers: vector, deque and list. In addition, arrays, which are a built-in part of the language and the string class, which is part of the standard library, may be used as sequence containers. The associative containers are specialized to allow the fastest possible retrieval (or look up) of values. This retrieval is either by the values themselves or by a key, where each value has its own key. There are four standard associated containers that will be part of any implementation of the standard C++ library: set, multiset, map and multimap. Iterators provide a way of specifying a position in a container. An iterator can be incremented or dereferenced, and two iterators can be compared. There is a special iterator value called "past-the-end". Algorithms: The STL algorithms are template C++ functions to perform operations on containers. In order to be able to work with many different types of containers, the algorithms do not take containers as arguments. Instead, they take iterators that specify part or all of a container. The algorithms include sorting operations (sort, merge, min, max...), searching operations (find, count, equal...), mutating operations (transform, replace, fill, rotate, shuffle...), and generalized numeric operations (accumulate, adjacent difference...).

string str18 = "abcdefghi"

string str19 = str18.substr (6,2);

cout << str19 << endl; // "gh"

string str10 = "abcdefghi";

char ch = str10[3];

cout << ch << endl; // 'd'

str10[5] = 'X';

cout << str10 << endl; // "abcdeXghi"

}

Page 92: C++_Mat - Must Go through

C++ Programming

92

The example below shows how vector container is used to perform operations for an integer array.

Example 14.2 Example of Vector Container

#include <algorithm>

#include <iostream>

#include <vector>

using namespace std;

int main( void )

{

int ival, nitems = 0;

vector < int >v; // v is instance of vector class

//instantiated for int type

cout << "Enter integers, <Return>after each,<ctrl> Z

to finish:" << endl;

while( cin >> ival, cin.good() )

{

v.push_back( ival );

//push_back is member function that

//adds an element to the vector

cout.width(6);

cout << nitems << ": "

<< v[nitems++] << endl;

}

if ( nitems )

{

vector::Iterator vib = v.begin();

// an Iterator pointing to

beginning //of the vector

sort( vib, v.end() );

// v.end is an iterartor , sort is

an //algorithm accepting 2 iterator

arguments

for (vector::const_iterator viter=v.begin();

viter!=v.end(); ++viter)

cout << *viter << " ";

}

return( 0 );

}