ADS Unit II
ADS Unit II
Function Overloading
Overloading Constructors
1. To Gain Flexibility:
UNIT II 1
Ex1: #include <iostream.h>
class powers
{
int x;
public:
// overload constructor two ways
powers() { x = 0; } // no initializer
powers(int n) { x = n; } // initializer
int main()
{
powers ofTwo[] = {1, 2, 4, 8, 16}; // initialized
powers ofThree[5]; // uninitialized
powers *p;
int i;
delete [] p;
return 0;
UNIT II 2
3. Copy Constructors:
NOTE:
UNIT II 3
The copy constructor applies only to initializations.
Ex2: #include <iostream.h>
class array
{ int *p;
int size;
public:
array(int sz)
{ p = new int[sz];
size = sz;
}
~array() { delete [] p; }
p = new int[a.size];
for(i=0; i<a.size; i++)
p[i] = a.p[i];
}
int main()
{ array num(10);
int i;
UNIT II 4
}
Default Function Arguments
• Many of C++ I/O functions make use of default arguments for just
this reason.
int main()
{
iputs("Hello there", 10);
iputs("This will be indented 10 spaces by default");
iputs("This will be indented 5 spaces", 5);
iputs("This is not indented", 0);
return 0;
}
if(indent >= 0)
i = indent;
else // reuse old indent value
indent = i;
UNIT II 5
}
• All parameters that take default values must appear to the right
of those that do not.
Ex4:
#include <iostream.h>
class cube
{
int x, y, z;
public:
cube(int i=0, int j=0, int k=0)
{
x=i;
y=j;
z=k;
}
int volume()
{
return x*y*z;
}
};
int main()
{
cube a(2,3,4), b;
return 0;
}
UNIT II 6
OPERATOR OVERLOADING
• General form :
Ret-type classname :: operator#(arg-list)
{
// operations
}
• When overloading a unary operator, argument list will be
empty.
• When overloading a binary operator, argument list will have 1
parameter.
• An operator function can return any type and the type returned
depends solely upon the specific application.
UNIT II 7
Ex1: overloading +
#include <iostream.h>
class loc
{
int longitude, latitude;
public:
loc() {}
loc(int lg, int lt)
{
longitude = lg;
latitude = lt;
}
void show()
{
cout << longitude << " ";
cout << latitude << "\n";
}
return temp;
}
int main()
{
loc ob1(10, 20), ob2( 5, 30);
ob1.show(); // displays 10 20
ob2.show(); // displays 5 30
return 0;
UNIT II 8
}
NOTE:
The reason the binary operator function takes only one parameter is
that the operand on the left side of the operator is passed
implicitly to the function through the this pointer. The operand on
the right is passed in the parameter.
Ex2: overloading –
return temp;
}
Ex3: overloading =
UNIT II 9
Ex4: overloading ++ (prefix form)
loc loc::operator++()
{
longitude++;
latitude++;
return *this;
}
return *this;
}
NOTE:
Before decoupling an overloaded operator from its normal meaning, be
sure to have a sufficient reason to do so. One good example where
UNIT II 10
decoupling is successful is in the way << and >> are overloaded in
C++.
OPERATOR OVERLOADING USING A FRIEND FUNCTION
#include <iostream.h>
class loc
{
int longitude, latitude;
public:
loc() {} // needed to construct temporaries
loc(int lg, int lt)
{
longitude = lg;
latitude = lt;
}
void show()
{
cout << longitude << " ";
cout << latitude << "\n";
}
UNIT II 11
return temp;
}
Restrictions for friend operator functions
class loc
{
int longitude, latitude;
public:
loc() {}
loc(int lg, int lt)
{
longitude = lg;
latitude = lt;
}
void show()
{
cout << longitude << " ";
cout << latitude << "\n";
}
return op;
}
UNIT II 12
return op;
}
Friend operator functions add flexibility
• Assume a class that defines operator+() function that adds an
object of the class to integer. Then,
o Ob + 100; is valid
o 100 + Ob; is invalid
• To allow both versions, simply overload + using a friend
function and overload this function twice – one version for each
situation.
Ex:
#include <iostream.h>
class loc
{
int longitude, latitude;
public: loc() {}
loc(int lg, int lt)
{
longitude = lg;
latitude = lt;
}
void show()
{
cout << longitude << " ";
cout << latitude << "\n";
}
friend loc operator+(loc op1, int op2);
friend loc operator+(int op1, loc op2);
};
UNIT II 13
NOTE: ob1 = ob2 + 10; ob3 = 10 + ob2; // both of these are valid
OVERLOADING SPECIAL OPERATORS
Restriction –
• They must be nonstatic member functions.
• They cannot be friends.
1. Overloading []
• In C++ the [] is considered as binary operator when
overloading it.
• General syntax : type classname :: operator[] (int i)
{ // function body
}
Ex1:
#include <iostream.h>
class atype
{
int a[3];
public:
atype(int i, int j, int k)
{
a[0] = i;
a[1] = j;
a[2] = k;
}
int operator[](int i)
{
return a[i];
}
};
int main()
{
atype ob(1, 2, 3);
UNIT II 14
return 0;
}
The operator[] can be designed in such a way that [] can be used both
on left & right sides of an assignment statement.
Ex2:
#include <iostream.h>
class atype
{
int a[3];
public:
atype(int i, int j, int k)
{
a[0] = i;
a[1] = j;
a[2] = k;
}
int &operator[](int i)
{
return a[i];
}
};
int main()
{
atype ob(1, 2, 3);
return 0;
}
NOTE:
UNIT II 15
subscripting operator, then the out-of-range index can be
intercepted.
2. Overloading ()
• When we overload the () function call operator, we are not
creating a new way to call a function. Rather, we are
creating an operator function that can be passed an
arbitrary number of parameters.
Ex:
double operator()(int a, float f, char *s);
An object O of this class, then the statement
O(10, 23.34, "hi");
Translates into the call as -
O.operator()(10, 23.34, "hi");
UNIT II 16
NOTE: ob1 = ob2 + ob1(10, 10); // can be used in expressions
3. Overloading ->
• The -> pointer operator, also called the class member access
operator, is considered a unary operator when overloading.
Ex:
#include <iostream.h>
class myclass
{
public:
int i;
myclass *operator->()
{
return this;
}
};
int main()
{
myclass ob;
return 0;
}
NOTE:
UNIT II 17
OVERLOADING THE COMMA OPERATOR
• Comma is a binary operator.
• If the overloaded comma is to perform in a fashion similar to
its normal operation, then the values of all operands, except
the rightmost, has to be discarded.
Ex:
#include <iostream.h>
class loc
{
int longitude, latitude;
public:
loc() {}
loc(int lg, int lt)
{ longitude = lg;
latitude = lt;
}
void show()
{ cout << longitude << " ";
cout << latitude << "\n";
}
loc operator+(loc op2);
loc operator,(loc op2);
};
temp.longitude = op2.longitude;
temp.latitude = op2.latitude;
cout << op2.longitude <<" "<< op2.latitude << "\n";
return temp;
}
int main()
{ loc ob1(10, 20), ob2( 5, 30), ob3(1, 1);
ob1.show(); ob2.show(); ob3.show(); cout << "\n";
return 0;
}
UNIT II 18
NOTE: The left-hand operand is passed via this and its value is
discarded by the operator,() function. The value of the right-hand
operand is returned by the function.
INHERITANCE
o Public
o private (default) or
o protected.
• When the access specifier for the base class is public, all
public members of the base become public members of the derived
class and all protected members of the base become protected
members of the derived class.
UNIT II 19
Inheritance and Protected members
• When this is done, all public & protected members of the base
class become protected members of the derived class.
UNIT II 20
• Use an access-specifier for each base class inherited.
Constructors, Destructors and Inheritance
Ex1:
#include <iostream.h>
class base
{
protected:
int i;
public:
base(int x)
{ i=x;
cout << "Constructing base\n";
}
~base()
{
cout << "Destructing base\n";
}
};
int main()
{
derived ob(3, 4);
ob.show(); // displays 4 3
UNIT II 21
return 0;
}
Ex2: #include <iostream.h>
class base1
{
protected: int i;
public:
base1(int x)
{ i=x;
cout << "Constructing base1\n";
}
~base1()
{ cout << "Destructing base1\n"; }
};
class base2
{
protected: int k;
public:
base2(int x)
{ k=x;
cout << "Constructing base2\n";
}
~base2()
{ cout << "Destructing base1\n"; }
};
int main()
{
derived ob(3, 4, 5);
ob.show(); // displays 4 3 5
return 0;
}
UNIT II 22
NOTE: C++ allows dynamic initialization.
VIRTUAL BASE CLASSES
class base
{
public: int i;
};
class derived1 : public base
{
public: int j;
};
class derived2 : public base
{
public: int k;
};
int main()
{
derived3 ob;
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
UNIT II 23
return 0;
}
There are 2 ways to solve this problem :
Ex:
#include <iostream.h>
class base
{
public: int i;
};
int main()
{
derived3 ob;
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
return 0;
}
UNIT II 24
2. If only one copy of the base is actually required, then we need
to prevent 2 copies from being included in derived3.This
solution is achieved using virtual-base classes.
Declare the base class as virtual when it is inherited.
Ex:
#include <iostream.h>
class base
{
public: int i;
};
class derived1 : virtual public base
{
public: int j;
};
class derived2 : virtual public base
{
public: int k;
};
int main()
{
derived3 ob;
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
return 0;
}
NOTE:
UNIT II 25
Even if the base is virtual, base is still present in objects of
either type.
VIRTUAL FUNCTIONS AND POLYMORPHISM
VIRTUAL FUNCTIONS
UNIT II 26
Ex: #include <iostream.h>
class base
{
public:
virtual void vfunc()
{
cout << "This is base's vfunc().\n";
}
};
int main()
{
base *p, b;
derived1 d1;
derived2 d2;
return 0;
UNIT II 27
}
UNIT II 28
Ex:
#include <iostream.h>
class base
{
public:
virtual void vfunc()
{
cout << "This is base's vfunc().\n";
}
};
class derived1 : public base
{
public:
void vfunc()
{
cout << "This is derived1's vfunc().\n";
}
};
class derived2 : public base
{
public:
void vfunc()
{
cout << "This is derived2's vfunc().\n";
}
};
int main()
{
base b;
derived1 d1;
derived2 d2;
return 0;
}
UNIT II 29
The virtual Attribute is inherited
• General form :
UNIT II 30
Ex: #include <iostream.h>
class number
{
protected: int val;
int main()
{
dectype d;
hextype h;
octtype o;
return 0;
UNIT II 31
}
Abstract classes
UNIT II 32
#include <iostream.h>
class convert
{ protected: double val1; // initial value
double val2; // converted value
public:
convert(double i)
{ val1 = i;
}
double getconv()
{ return val2; }
double getinit()
{ return val1; }
p = &fcob;
cout << p->getinit() << " in Fahrenheit is ";
p->compute();
cout << p->getconv() << " Celsius\n"; // f_to_c
return 0;
UNIT II 33
}
TEMPLATES
GENERIC FUNCTIONS
• The type of data that the function will operate upon is passed
to it as a parameter.
o General Form:
template<class Ttype>
Ret-type function-name(parameter list)
{
// body
}
UNIT II 34
Ex:
#include <iostream.h>
temp = a;
a = b;
b = temp;
}
int main()
{
int i=10, j=20;
double x=10.1, y=23.3;
char a='x', b='z';
cout << "Original i, j: " << i << ' ' << j << '\n';
cout << "Original x, y: " << x << ' ' << y << '\n';
cout << "Original a, b: " << a << ' ' << b << '\n';
return 0;
}
UNIT II 35
• A generic function is also called a template function.
• When the compiler creates a specific version of this function,
it is said to have created a specialization. This is also called
a generated function.
• The act of generating a function is referred to as instantiating
it.
• Put differently, a generated function is a specific instance of
a template function.
More than one generic data type can be defined in the template
statement by using a comma-seperated list.
Ex:
#include <iostream.h>
int main()
{
myfunc(10, "I like C++");
myfunc(98.6, 19L);
return 0;
}
Note:
UNIT II 36
Explicitly Overloading a Generic Function
temp = a;
a = b;
b = temp;
cout << "Inside template swapargs.\n";
}
cout << "Swapped i, j: " << i << ' ' << j << '\n';
cout << "Swapped x, y: " << x << ' ' << y << '\n';
cout << "Swapped a, b: " << a << ' ' << b << '\n';
return 0;
UNIT II 37
}
new style-syntax to explicitly overload a template function
template< >
void swapargs<int>(int &a,int &b)
{ // function body
}
Ex:
#include <iostream.h>
int main()
{
f(10); // calls f(X)
f(10, 20); // calls f(X, Y)
return 0;
}
UNIT II 38
Using Standard Parameters with Template Functions
Ex:
int main()
{
show(10,10);
show(15.5,10);
show(“Templates”,10);
return 0;
}
A generic function must perform the same general action for all
versions – only the type of data can differ.
• Once we have done so,we may use it with any type of data without
having to recode it.
UNIT II 39
Ex:// A generic bubble sort
#include <iostream.h>
int main()
{
int iarray[7] = {7, 5, 4, 3, 9, 8, 6};
double darray[5] = {4.3, 2.5, -0.9, 100.2, 3.0};
int i;
bubble(iarray, 7);
bubble(darray, 5);
return 0;
}
UNIT II 40
GENERIC CLASSES
• Generic classes are useful when a class uses logic that can be
generalized.
o General form :
template<class Ttype>
class class-name
{
//body
}
o class-name<type> ob;
o Here, type is the type name of the data that the class
will be operating upon.
UNIT II 41
• A template class can have more than one generic data type.
Ex:
/* This example uses two generic data types in a
class definition.*/
#include <iostream.h>
Type2 j;
public:
myclass(Type1 a, Type2 b)
{ i = a; j = b;
}
void show()
{ cout << i << ' ' << j << '\n';
}
};
int main()
{
myclass<int, double> ob1(10, 0.23);
return 0;
}
UNIT II 42
Applying Template Classes: A generic safe array example.
#include <iostream.h>
#include <cstdlib.h>
const int SIZE = 10;
int i;
UNIT II 43
}
Using Non-Type Arguments with Generic Classes
UNIT II 44
Ex: // Demonstrate class specialization.
#include <iostream.h>
template <>
class myclass<int>
{
int x;
public: myclass(int a)
{ cout << "In myclass<int> specialization\n";
x = a * a;
}
int getx() { return x; }
};
int main()
{
myclass<double> d(10.1);
cout << "double: " << d.getx() << "\n\n";
myclass<int> i(5);
cout << "int: " << i.getx() << "\n";
return 0;
}
UNIT II 45
only specifying its declaration rather than duplicating its
entire definition.
UNIT II 46