Unit 5 Lec Notes
Unit 5 Lec Notes
Binding refers to the process of converting identifiers (such as variable and performance names) into
addresses. Binding is done for each variable and functions. For functions, it means that matching the
call with the right function definition by the compiler. It takes place either at compile time or at runtime.
Early Binding (compile-time time polymorphism): As the name indicates, compiler (or linker)
directly associate an address to the function call. It replaces the call with a machine language instruction
that tells the mainframe to leap to the address of the function. By default early binding happens in C++.
Example:
#include<iostream.h>
class Base
{
public:
void show() { cout<<" In Base \n"; }
};
class Derived: public Base
{
public:
void show() { cout<<"In Derived \n"; }
};
int main(void)
{
Base *bp = new Derived;
return 0;
}
Late Binding : (Run time polymorphism): In this, the compiler adds code that identifies the kind of
object at runtime then matches the call with the right function definition. This can be achieved by
declaring a virtual function.
#include<iostream.h>
class Base
{
public:
virtual void show() { cout<<" In Base \n"; }};
class Derived: public Base
{
public:
void show() { cout<<"In Derived \n"; }};
int main(void)
{
Base *bp = new Derived;
bp->show(); // RUN-TIME POLYMORPHISM
return 0;}
o A virtual function is a member function in the base class that you redefine in a derived class. It is
declared using the virtual keyword.
o It is used to tell the compiler to perform dynamic linkage or late binding on the function.
o There is a necessity to use the single pointer to refer to all the objects of the different classes. So,
we create the pointer to the base class that refers to all the derived objects. But, when base class
pointer contains the address of the derived class object, always executes the base class function.
This issue can only be resolved by using the 'virtual' function.
o A 'virtual' is a keyword preceding the normal declaration of a function.
o When the function is made virtual, C++ determines which function is to be invoked at the runtime
based on the type of the object pointed by the base class pointer.
#include <iostream.h>
class A
{
int x=5;
public:
void display()
{
cout << "Value of x is : " << x<< endl;
}
};
class B: public A
{
int y = 10;
public:
void display()
{
cout << "Value of y is : " <<y<< endl;
}
};
int main()
{
A *a;
B b;
a = &b;
a->display();
return 0;
}
In the above example, * a is the base class pointer. The pointer can only access the base class
members but not the members of the derived class. Although C++ permits the base pointer to point to any
object derived from the base class, it cannot directly access the members of the derived class. Therefore,
there is a need for virtual function which allows the base pointer to access the members of the derived
class.
Virtual function Example {
#include <iostream.h> cout << "Derived Class is invoked"<<endl;
{
public: }
virtual void display() };
{ int main()
cout << "Base class is invoked"<<endl; {
} A* a; //pointer of base class
}; B b; //object of derived class
class B:public A a = &b;
{ a->display(); //Late Binding occurs
public: }
void display()
o When the function has no definition, such function is known as "do-nothing" function.
o The "do-nothing" function is known as a pure virtual function. A pure virtual function is a
function declared in the base class that has no definition relative to the base class.
o A class containing the pure virtual function cannot be used to declare the objects of its own, such
classes are known as abstract base classes.
o The main objective of the base class is to provide the traits to the derived classes and to create the
base pointer used for achieving the runtime polymorphism.
An abstract class in C++ is a class that has at least one pure virtual function (i.e., a function that has no
definition). The classes inheriting the abstract class must provide a definition for the pure virtual function;
otherwise, the subclass would become an abstract class itself.
Abstract classes are essential to providing an abstraction to the code to make it reusable and extendable.
For example, a Vehicle parent class with Truck and Motorbike inheriting from it is an abstraction that
easily allows more vehicles to be added. However, even though all vehicles have wheels, not all vehicles
have the same number of wheels – this is where a pure virtual function is needed.
Consider an example of a Shape base class with sub-classes (Triangle and Rectangle) that inherit
the Shape class.
Now, suppose we need a function to return the area of a shape. The function will be declared in
the Shape class; however, it cannot be defined there as the formula for the area is different for each shape.
A non-specific shape does not have an area, but rectangles and triangles do. Therefore, the pure virtual
function for calculating area will be implemented differently by each sub-class.
The following code snippet implements the abstract Shape class along with its sub-classes
#include <iostream.h>
class Shape {
public:
virtual int Area() = 0; // Pure virtual function is declared as follows.
// Function to set width.
void setWidth(int w) {
width = w;
}
// Function to set height.
void setHeight(int h) {
height = h;
}
protected:
int width;
int height;
};
// A rectangle is a shape; it inherits shape.
class Rectangle: public Shape {
public:
// The implementation for Area is specific to a rectangle.
int Area() {
return (width * height);
}
};
// A triangle is a shape too; it inherits shape.
class Triangle: public Shape {
public:
// Triangle uses the same Area function but implements it to
// return the area of a triangle.
int Area() {
return (width * height)/2;
}
};
int main() {
Rectangle R;
Triangle T;
R.setWidth(5);
R.setHeight(10);
T.setWidth(20);
T.setHeight(8);
cout << "The area of the rectangle is: " << R.Area() << endl;
cout << "The area of the triangle is: " << T.Area() << endl;
}
Virtual Destructor
Deleting a derived class object using a pointer of base class type that has a non-virtual destructor results
in undefined behavior. To correct this situation, the base class should be defined with a virtual
destructor. For example, following program results in undefined behavior.
// CPP program without virtual destructor
// causing undefined behavior#include<iostream.h>
class base {
public:
base()
{ cout<<"Constructing base \n"; }
~base()
{ cout<<"Destructing base \n"; }
};
class derived: public base {
public:
derived()
{ cout<<"Constructing derived \n"; }
~derived()
{ cout<<"Destructing derived \n"; }
};
int main(void)
{
derived *d = new derived();
base *b = d;
delete b;
getchar();
return 0;
}
OUTPUT
Constructing base
Constructing derived
Destructing base
Making base class destructor virtual guarantees that the object of derived class is destructed properly,
both base class and derived class destructors are called.
Exception Handling:
An exception is a problem that arises during the execution of a program. A C++ exception is a response
to an exceptional circumstance that arises while a program is running, such as an attempt to divide by
zero. Exceptions provide a way to transfer control from one part of a program to another. C++ exception
handling is built upon three keywords: try, catch, and throw.
throw − A program throws an exception when a problem shows up. This is done using
a throw keyword.
catch − A program catches an exception with an exception handler at the place in a program
where you want to handle the problem. The catch keyword indicates the catching of an exception.
try − A try block identifies a block of code for which particular exceptions will be activated. It's
followed by one or more catch blocks.
Assuming a block will raise an exception, a method catches an exception using a combination of
the try and catch keywords. A try/catch block is placed around the code that might generate an
exception. Code within a try/catch block is referred to as protected code, and the syntax for using
try/catch as follows −
try
{
// protected code
}
catch( Exception Name e1 )
{
// catch block
}
catch( Exception Name e2 )
{
// catch block
}
catch( Exception Name eN )
{
// catch block
}
You can list down multiple catch statements to catch different type of exceptions in case your try block
raises more than one exception in different situations.
Throwing Exceptions
Exceptions can be thrown anywhere within a code block using throw statement. The operand of the
throw statement determines a type for the exception and can be any expression and the type of the result
of the expression determines the type of exception thrown.
Catching Exceptions
The catch block following the try block catches any exception. You can specify what type of exception
you want to catch and this is determined by the exception declaration that appears in parentheses
following the keyword catch.
try {
// protected code
}
catch( ExceptionName e )
{
// code to handle Exception Name exception }
Above code will catch an exception of Exception Name type. If you want to specify that a catch block
should handle any type of exception that is thrown in a try block, you must put an ellipsis, ..., between the
parentheses enclosing the exception declaration as follows −
try {
// protected code
}
catch(...)
{
// code to handle any exception
}
The following is an example, which throws a division by zero exception and we catch it in catch block.
#include <iostream.h>
double division(int a, int b)
{
if( b == 0 )
{
throw "Division by zero condition!";
}
return (a/b);
}
int main () {
int x = 50;
int y = 0;
double z = 0;
try {
z = division(x, y);
cout << z << endl;
}
catch (const char* msg)
{ cerr << msg << endl;
}
return 0;
}
Templates
A C++ template is a powerful feature added to C++. It allows you to define the generic classes and generic
functions and thus provides support for generic programming. Generic programming is a technique where
generic types are used as parameters in algorithms so that they can work for a variety of data types.
o Function templates
o Class templates
1. Function Templates:
We can define a template for a function. For example, if we have an add() function, we can create versions
of the add function for adding the int, float or double type values.
2. Class Template:
We can define a template for a class. For example, a class template can be created for the array class that
can accept the array of various types such as int array, float array or double array.
Function Template
o Generic functions use the concept of a function template. Generic functions define a set of
operations that can be applied to the various types of data.
o The type of the data that the function will operate on depends on the type of the data passed as a
parameter.
o For example, Quick sorting algorithm is implemented using a generic function, it can be
implemented to an array of integers or array of floats.
o A Generic function is created by using the keyword template. The template defines what function
will do.
Syntax of Function Template:
template < class Ttype> ret_type func_name(parameter_list)
{
// body of function. }
Where Ttype: It is a placeholder name for a data type used by the function. It is used within the function
definition. It is only a placeholder that the compiler will automatically replace this placeholder with the
actual data type.
class: A class keyword is used to specify a generic type in a template declaration.
example of a function template:
#include <iostream.h>
template<class T>
T add(T &a,T &b)
{
T result = a+b;
return result;
}
int main()
{
int i =2;
int j =3;
float m = 2.3;
float n = 1.2;
cout<<"Addition of i and j is :"<<add(i,j);
cout<<'\n';
cout<<"Addition of m and n is :"<<add(m,n);
return 0;
}
Output:
Addition of i and j is :5
Addition of m and n is :3.5
In the above example, we create the function template which can perform the addition operation on any
type either it can be integer, float or double.
Function Templates with Multiple Parameters
We can use more than one generic type in the template function by using the comma to separate the list.
Syntax :
template<class T1, class T2,.....>
return_type function_name (arguments of type T1, T2....)
{
// body of function.
}
In the above syntax, we have seen that the template function can accept any number of arguments of a
different type.
example:
#include <iostream.h>
template<class X,class Y>
void fun(X a,Y b)
{
cout << "Value of a is : " <<a<< endl;
cout << "Value of b is : " <<b<< endl;
}
int main()
{
fun(15,12.3);
return 0;
}
Output:
Value of a is : 15
Value of b is : 12.3
In the above example, we use two generic types in the template function, i.e., X and Y.
void fun(int b)
{
if(b%2==0)
{
cout<<"Number is even";
}
else
{
cout<<"Number is odd";
} }
int main()
{
fun(4.6);
fun(6);
return 0;
}
Output:
value of a is : 4.6
Number is even
In the above example, we overload the ordinary functions. We cannot overload the generic functions as
both the functions have different functionalities. First one is displaying the value and the second one
determines whether the number is even or not.
CLASS TEMPLATE
Class Template can also be defined similarly to the Function Template. When a class uses the concept of
Template, then the class is known as generic class.
Syntax : template<class T type>
class class_name
{
.
. }
T type is a place holder name which will be determined when the class is instantiated. We can define
more than one generic data type using a comma-separated list. The T type can be used inside the class
body. Now, we create an instance of a class
class_name<type> ob;
where class_name: It is the name of the class.
type: It is the type of the data that the class is operating on.
Example:
#include <iostream.h>
template<class T>
class A
{
public:
T num1 = 5;
T num2 = 6;
void add()
{
cout << "Addition of num1 and num2 : " << num1+num2<< endl;
} };
int main()
{
A<int> d;
d.add();
return 0;
}
Output:
Addition of num1 and num2 : 11
In the above example, we create a template for class A. Inside the main() method, we create the instance
of class A named as, 'd'.
CLASS TEMPLATE WITH MULTIPLE PARAMETERS
We can use more than one generic data type in a class template, and each generic data type is separated by
the comma.
Syntax: template<class T1, class T2, ......>
class class_name
{
// Body of the class. }
simple example when class template contains two generic data types.
#include <iostream.h>
template<class T1, class T2>
class A
{
T1 a;
T2 b;
public:
A(T1 x,T2 y)
{
a = x;
b = y;
}
void display()
{
cout << "Values of a and b are : " << a<<" ,"<<b<<endl;
}
};
int main()
{
A<int,float> d(5,6.5);
d.display();
return 0;
}
Output:
Values of a and b are : 5,6.5
Non type Template Arguments
The template can contain multiple arguments, and we can also use the non-type arguments In addition to
the type T argument, we can also use other types of arguments such as strings, function names, constant
expression and built-in types.
example:
template<class T, int size>
class array
{
T arr[size]; // automatic array initialization.
};
In the above case, the nontype template argument is size and therefore, template supplies the size of the
array as an argument.
Arguments are specified when the objects of a class are created:
void display()
{
for(int i=0;i<size;i++)
{
cout << arr[i] << " ";
} } };
int main()
{
A<int,10> t1;
t1.insert();
t1.display();
return 0;
}
Output:
1 2 3 4 5 6 7 8 9 10
In the above example, the class template is created which contains the nontype template argument, i.e.,
size. It is specified when the object of class 'A' is created.
Points to Remember
o C++ supports a powerful feature known as a template to implement the concept of generic
programming.
o A template allows us to create a family of classes or family of functions to handle different data
types.
o Template classes and functions eliminate the code duplication of different data types and thus
makes the development easier and faster.
o Multiple parameters can be used in both class and function template.
o Template functions can also be overloaded.
o We can also use non type arguments such as built-in or derived data types as template arguments.