BCS306B - Module 3
BCS306B - Module 3
OPERATOR OVERLOADING
Operator overloading is an example of C++ polymorphism. For example, the ‘+’
operator can be used to carry out four different operations such as adding two integers,
adding two real numbers, concatenating two strings and adding two class objects, thereby +
gets overloaded. When a ‘+’ operator is used with two ints (integers) has different meaning as
compared when it is applied to object manipulation.
The main advantage of using overloading in our programs is, it is more natural to
read, write and debug.
Defining Operator Overloading:
The C++ has the ability to provide the operator with a special meaning for a data type.
The mechanism of giving such special meanings to an operator is known as operator
overloading.
Operator overloading is accomplished by means of a special kind of function called
Operator Function, which describes the task. The general form of an operator function is as
follows:
return type classname :: operator opr(argument list)
{
function body;
}
where, return-type - is the data type of the return value.
class-name - name of the class
:: - scope resolution operator
operator - is a keyword
opr - is a C++’s built-in operator (overloaded). It may be an unary
operator or binary operator
argument list - is a list of arguments to be passed
operator opr - is the function name
For example,
1. void sample :: operator * (sample s1, sample s2)
{
//function body
}
Here, * is overloaded to perform multiplication of two objects of class sample.
2. void string :: operator + (string str1, string str2)
{
//string concatenation
}
Here, + is overloaded to add two objects (concatenation) of class String.
= Assignment operator
() Function call operator
[] Subscripting operator
-> Class member access operator
7. Unary operators, overloaded by means of a member function, take no explicit
arguments and return no explicit values, but, those overloaded by means of a friend
function, take one reference argument (the object of the relevant class).
8. Binary operators overloaded through a member function take one explicit argument
and those which are overloaded through a friend function take two explicit arguments.
9. When using binary operators overloaded through a member function, the left hand
operand must be an object of the relevant class.
10. Binary arithmetic operators such as +, –, *, and / must explicitly return a value. They
must not attempt to change their own arguments.
Overloading Unary Operators:
Unary operators overloaded by member functions take no formal arguments, whereas
when they are overloaded by friend functions they take a single argument.
Let us consider the unary minus operator. A minus operator when used as a unary
takes just one operand. This operator changes the sign of an operand when applied to a basic
data item. This will be applied to an object in the same way as it applied to an int or float.
The unary minus when applied to an object should change the sign of each of its data items.
Program to illustrate overloading unary operator using member function.
#include<iostream.h>
#include<conio.h>
class sample
{
int x,y,z;
public:
void getdata(int a, int b, int c)
{
x = a; y = b; z = c;
}
void display(void)
{
cout<<x<<"\t"<<y<<"\t"<<z<<endl;
}
void operator-();
};
void sample ::operator -()
{
x = -x; y = -y; z = -z;
}
void main()
{
sample s;
OUTPUT:
[Link](10, -20, 30);
s : 10 -20 30
cout<<"s : "; s : -10 20 -30
[Link]();
-s; //operator overloaded
cout<<"s : ";
[Link]();
}
Note: The function operator –( ) take no argument. It changes the sign of data
members of the object S. Since this function is a member of the same class, it can directly
access the members of the object which activated it.
Overloading Binary Operators:
Binary operators overloaded by means of member functions take one formal
argument, which is the value to the right of the operator. Binary operators, overloaded by
means of friend functions take two arguments.
//Write a program to add two timing by overloading the operator +( ) using member
function
class time
{
int hr,min,sec;
public:
void gettime()
{
cout<<"Enter the hour, min and sec\n";
cin>>hr>>min>>sec;
}
void puttime()
{
cout<<hr<<"\t"<<min<<"\t"<<sec<<endl;
}
time operator +(time t);
};
time time :: operator +(time t)
{
time temp;
[Link] = hr + [Link];
[Link] = min + [Link];
[Link] = sec + [Link];
while([Link] >= 60)
{
[Link] = [Link] - 60;
[Link]++; OUTPUT:
} Enter the I time
while([Link] >= 60) Enter the hour, min and sec
2
{ 45
[Link] = [Link] - 60; 30
[Link]++;
Enter the II time
} Enter the hour, min and sec
return temp; 3
} 30
void main() 45
{ Given Timings
time t1,t2,t3; Hour Minutes Seconds
cout <<"\nEnter the I time\n"; 2 45 30
3 30 45
[Link]();
cout <<"\nEnter the II time\n"; Total=6 16 15
[Link]();
cout <<"\nGiven Timings\n";
cout<<"Hour\tMinutes\tSeconds\n";
[Link]();
[Link]();
t3 = t1 + t2; //operator overloaded
cout<<"\nTotal= ";
[Link]();
}
Overloading Binary Operators Using Friend:
Friend functions may be used in the replace of member functions for overloading a
binary operator, the only difference being that a friend function requires two arguments to be
explicitly passed to it, while a member function requires only one.
The time program discussed in the previous section can be modified using a friend
operator function by replacing the member function declaration by the friend function
declaration.
time operator +(time t1, time t2)
In this case, the statement
t3 = t1 + t2;
is equivalent to
t3 = operator +(t1, t2);
//Program to add two timing by overloading the + operator Using friend function
class time
{
int hr,min,sec;
public:
void gettime()
{
cout<<"Enter the hours\n";
cin>>hr;
cout<<"Enter the minutes\n";
cin>>min;
cout<<"Enter the seconds\n";
cin>>sec;
}
void puttime()
{
cout<<"\t"<<hr<<"\t"<<min<<"\t"<<sec<<endl;
}
friend time operator +(time t1,time t2);
};
time operator + (time t1,time t2)
{ OUTPUT:
time temp; Enter the I time
[Link] = [Link] + [Link]; Enter the hours
2
[Link] = [Link] + [Link];
Enter the minutes
[Link] = [Link] + [Link]; 45
while([Link] >= 60) Enter the seconds
45
{
[Link] = [Link] - 60; Enter the II time
[Link]++; Enter the hours
} 3
Enter the minutes
while([Link] >= 60) 30
{ Enter the seconds
[Link] = [Link] - 60; 30
[Link]++;
Given Timings
} Hour Minutes Seconds
return temp; 2 45 30
3 30 45
}
void main() Total = 6 16 15
{
time t1,t2,t3;
cout <<"\nEnter the I time\n";
[Link]();
cout <<"\nEnter the II time\n";
[Link]();
cout <<"\nGiven Timings\n";
cout<<"\tHour\tMinutes\tSeconds\n";
[Link]();
[Link]();
t3 = t1 + t2;
cout<<"\nTotal = ";
[Link]();
getch();
}
INHERITANCE
Reusability is an important feature of OOP. The C++ strongly supports the concept of
reusability. The C++ classes can be reused in several ways. Once a class has been written
and tested, it can be adapted by other programmers to suit their requirements. This is
basically done by creating new classes and reusing the properties of the existing ones.
A process of deriving a new class from an existing class is called inheritance. The old
class is referred to as the base class (Parent class) and the new one is called the derived class
or subclass (Child class).
In other words, Inheritance is the process of acquiring (copying) the properties from
one class/object to another class/object.
In inheritance, some of the base class data elements and member functions are
‘inherited’ into the derived class. We can add our own data and member functions and thus
extend the functionality of the base class. Inheritance, when used to modify and extend the
capabilities of the existing classes, becomes a very powerful tool for incremental program
development.
Inheritance helps us to reuse the code. Reuse of code gives saving memory and time
of writing code; reduce the length of the program.
Base class and Derived class:
A derived class can be defined by specifying its relationship with the base class in
addition to its own details. The general form of defining a derived class is:
class derived_class_name : visibility-mode base-class-name
{
……. //members of derived class
};
where,
class - is a keyword
derived_class_name - name of the derived class
: - shows the derivation from the base-class
visibility mode - specifies the types of derivation
base-class-name - name of the base class
Examples: Case 1:
class derivedclass : private baseclass // private derivation
{
members of derivedclass;
};
When a base class is privately inherited a derived class, then ‘public members, and
‘protected members’ of the base class become ‘private members’ of the derived class and
therefore the public members and protected members of the base class can only be accessed
by the member functions of the derived class. They are inaccessible to the objects of the
derived class.
Case 2:
class derivedclass : public baseclass // public derivation
{
members of derivedclass
};
When the base class is publicly inherited, ‘public members’ and ‘protected
members’ of the base class become ‘public members’ and ‘protected members’ of the derived
class respectively and therefore ‘public members’ are accessible to the objects of the derived
class but ‘protected members’ are inaccessible to the objects of the derived class.
Case 3:
class derivedclass : protected baseclass //protected derivation
{
members of derivedclass
};
When the base class is protectedly inherited, then ‘public members, and ‘protected
members’ of the base class become ‘protected members’ of the derived class and therefore
the public members and protected members of the base class can only be accessed by the
member functions of the derived class. They are inaccessible to the objects of the derived
class.
Case 4:
class derivedclass : baseclass //private derivation by default
{
members of derivedclass
};
When a base class is inherited a derived class without any visibility mode, then it
mean it is privately inherited by default. (Same as Case 1).
NOTE: In all the above cases, the private members are not inherited and therefore,
the private members of a base class will never become the members of its derived class.
Following program illustrates the derived class object can directly access the public
members of the base class.
class baseclas
{
int x, y;
public:
void setvalue(int a, int b)
{
x = a;
y = b;
}
void display ( )
{
cout << x << “ ” << y << “\n” ;
}
};
class derivedclas : public baseclas
{
int z;
public:
derivedclas(int k)
{
z = k;
}
void displayz ( )
{
cout << z << “\n” ;
}
};
void main( )
{
derivedclas dob(5);
[Link](10, 20);
[Link]( );
[Link]( );
getch( );
}
Types of Inheritance:
A derived class extends its features by inheriting some or all the properties from its
base class and adding new features of its own. While inheriting, the derived class can share
properties from
class baseclas
{ baseclas
public: int x,y;
……. }; derivedclas
class derivedclas1 : public baseclas
{
public: int a,b; Single Inheritance
……
}; // Here, public members of baseclas are become public menbers of derivedclas.
2. Multiple Inheritance:
Multiple inheritance is a mechanism in which a new class is derived from more than
one class. It follows many-to-one relation.
class baseclas1
{
baseclas1 baseclas2 baseclas3
public: int x,y;
……
}; derivedclas
class baseclas2 Multiple Inheritance
{
public: int a,b;
……
};
class baseclas3
{
public: int m,n;
……
};
class derivedclas : public base1, public base2, public base3
{
……
};
Here, public members of all the 3 baseclasses are become public members of
derivedclas.
3. Multilevel inheritance:
Multilevel inheritance is a mechanism in which we derive a class from another
derived class. It’s just like grandfather-father-son relationship for exhibiting multilevel
inheritance. Class A serves as base class for the derived class B, which in turn serves as a
base class for the derived class C. Class B is known as intermediate base class since it
provides a link for the inheritance between A and C. The chain ABC is known as
inheritance path.
class A
{
public: int x,y;
……
};
class B : public A A Base class
{
public: int p, q; B Intermediate base class
};
class C : public B C Derived class
{
…… Multilevel Inheritance
};
Here, public members of calss A (i.e., x, y) become public member class B and
finally public members class B (i.e., p, q, x, and y) become public members of
derivedclas.
4. Hierarchical Inheritance:
Hierarchical inheritance is a mechanism in which the features of one class may be
inherited by more than one class. These classes, in turn, may be inherited. In the hierarchical
inheritance, there will be only one base class from which several other classes are created.
This form of inheritance follows one-to-many relationship. A derived class can be created by
deriving the properties of base class and adding its own properties.
class baseclas baseclas
{
public: int x, y;
…… derivedclas1 derivedclas2 derivedclas3
};
class derivedclas1 : public baseclas Hierarchical Inheritance
{
public: int p, q;
……
};
class derivedclas2 : public baseclas
{
public: int m, n;
…… };
class alpha
{
private: // optional
…… // visible to member functions within its class
protected:
……. //visible to member functions of its own and derived class
public:
…… //visible to all functions in the program
};
When a protected member is inherited in public mode, it becomes protected in the
derived class too and therefore is accessible by the member functions of the derived class. It
is also ready for further inheritance. A protected member, inherited in the private mode
derivation, becomes private in the derived class. Although it is available to the member
functions of the derived class, it is not available for further inheritance.
The keywords private, protected, and public may appear in any order and any
number of times in the declaration of a class. For example
class beta
{
protected:
……..
public:
……..
private:
……..
public:
……..
}; // is a valid class definition
Program illustrates the Inheritance and Protected Members.
class baseclas
{
protected: int x, y; //private to baseclas but accessible by derivedclas
public:
void setvalue(int a, int b)
{
x = a;
y = b;
}
void display ( )
{
cout << x << “ ” << y << “\n” ;
}
};
}
In the above program, main( ) function no need to call the baseclas and derivedclas
constructors and destructors explicitely as derivedclas object dob call them automatically.
In case of multi-level inheritance, the general rule applies i.e., Constructors are called
in order of derivation, but destructors are called in reverse order. For example
class baseclas
{
public:
baseclas ( )
{
cout << “The baseclas class Contructor is called \n”;
}
~baseclas ( )
{
cout << “The baseclas class Destructor is called \n”;
}
};
class derivedclas1 : public baseclas
{
public:
derivedclas1 ( )
{
cout << “The derivedclas1 class Contructor is called \n”;
}
~derivedclas1 ( )
{
cout << “The derivedclas1 class Destructor is called \n”;
}
};
class derivedclas2 : public derivedclas1
{
public:
derivedclas2 ( )
{
cout << “The derivedclas2 class Contructor is called \n”;
}
~derivedclas2 ( )
{
cout << “The derivedclas2 class Destructor is called \n”;
}
}; OUTPUT:
The baseclas class Contructor is called
void main( )
The derivedclas1 class Contructor is called
{ The derivedclas2 class Contructor is called
derivedclas2 dob2; The derivedclas2 class Destructor is called
getch( ); The derivedclas1 class Destructor is called
} The baseclas class Destructor is called
Suppose if our inheritance program contains multiple base classes, then also the same
general rule applies to invoke the constructor and destructor. For example
class baseclas1
{
public:
baseclas1 ( )
{
cout << “The baseclas1 class Contructor is called \n”;
}
~baseclas1 ( )
{
cout << “The baseclas1 class Destructor is called \n”;
}
};
class baseclas2
{
public:
baseclas2 ( )
{
cout << “The baseclas2 class Contructor is called \n”;
}
~baseclas2 ( )
{
cout << “The baseclas2 class Destructor is called \n”;
}
};
class derivedclas : public baseclas1, public baseclas2
{
public:
derivedclas ( )
{
cout << “The derivedclas class Contructor is called \n”;
}
~derivedclas ( )
{
cout << “The derivedclas class Destructor is called \n”;
} OUTPUT:
}; The baseclas1 class Contructor is called
The baseclas2 class Contructor is called
void main( )
The derivedclas class Contructor is called
{ The derivedclas class Destructor is called
derivedclas dob; The baseclas2 class Destructor is called
getch( ); The baseclas1 class Destructor is called
NOTE: Suppose if the derivedclas inherits the base classes in the following order,
then output will be in the respective order only. OUTPUT:
class derivedclas : public baseclas2, public baseclas2 The baseclas1 class Contructor is called
The baseclas2 class Contructor is called
The derivedclas class Contructor is called
The derivedclas class Destructor is called
The baseclas2 class Destructor is called
The baseclas1 class Destructor is called
class baseclas2
{
protected: int z;
public:
baseclas2 (int a)
{
z = a;
cout << “The baseclas2 class Contructor is called \n”;
}
~baseclas2 ( )
{
cout << “The baseclas2 class Destructor is called \n”;
}
};
class derivedclas : public baseclas1, public baseclas2
{
int y;
public:
derivedclas(int a, int b, int c) : baseclas1 (b), baseclas2 (c)
{
y = a;
cout << “The derivedclas class Contructor is called \n”;
}
~derivedclas ( )
{
cout << “The derivedclas class Destructor is called \n”;
}
void display( )
{
cout << x << “ “ << y<< “ “ << z << “\n”;
}
};
void main( )
{
derivedclas dob(10, 20, 30); OUTPUT:
20 10 30
[Link]( );
getch( );
}
In the above program, derivedclas’s constructor is declared as taking three
parameters, a, b, and c but it uses only a; b is passed along to baseclas1( ), and c is passed
along to baseclas2( )
~derivedclas ( )
{
cout << “The derivedclas class Destructor is called \n”;
}
void display( )
{
cout << x << “ “ << z << “\n”;
}
};
void main( ) OUTPUT:
{ 10 20
derivedclas dob(10, 20);
[Link]( );
}
In the above program, derivedclas’s constructor is declared as taking two parameters,
a, and b but it uses no parameters. a is passed along to baseclas1( ), and b is passed along to
baseclas2( ).
Granting Access:
In Inheritance, we know that, when a base class is privately inherited, then all public
and protected members of that class becomes private members of the derived class.
Sometimes it may necessary to use certain public members of the base class as public
members of derived class even though the base class is privately inherited.
In standard C++, we have two ways to accomplish this.
First, we can use a using statement with the support of namespaces concept (will
discuss this in later chapter).
Second, by declaring the required public member of base class with the base class
name followed by scope resolution operator followed by public member in public section of
the derived class. For example
Base-class-name :: public-members;
The following program illustrates the access declaration (Granting Access)
class baseclas
{
protected: int x;
public: int y, z;
void setx (int b)
{
x = b;
cout << “The baseclas class Contructor is called \n” ;
}
int getx( )
{
return x;
}
};
class derivedclas : private baseclas // Inherit baseclas privately
{
public:
baseclas :: y; // make y public here, but not the z
baseclas :: setx ( ); // make setx( ) function public here
baseclas :: getx ( ); // make getx( ) function public here
// baseclas :: x; // Illegal, We can’t elevate access
int a; // public
};
void main( )
{
derivedclas dob;
dob.x = 10; // Illegal as x is private in derived
dob.y = 20; // Legal as y is made public in derivedclas
dob.z = 30; // Illegal as z is private in derived
dob.a = 40; // Legal as a is public in derivedclas
[Link](10);
cout << [Link]( ) << “ “ << dob.y << “ “ << dob.a ;
}
Virtual Base Classes (Ambiguity in Multiple Inheritance):
When the same property of two base classes are inherited to single derived class then
the derived class will obtain two copies (from two base classes) of that same property to it.
While using this property, the compiler will get ambiguity (confusion) in multiple
inheritance.
There are two ways to overcome the ambiguity in multiple inheritance. The first to
apply the Scope Resolution Operator ( :: ) to that property and manually select the one copy
of the same property. The second way is to use the keyword virtual in all the derived class
definition before specify the visibility mode. So, the compiler will select any one of the same
property automatically.
For example, the following program illustrates how ambiguity occurs in both base
classes and the derived class and solution.
class baseclas
{
public: int x;
};
class derivedclas1 : public baseclas // derivedclas1 inherits baseclas
{
public: int y;
};
class derivedclas2 : public baseclas // derivedclas2 inherits baseclas
{
public: int z;
};
class derivedclas3 : public derivedclas1, public derivedclas2
{
// derivedclas3 inherits both derivedclas1
public: int total;
}; and derivedclas2. So there are two copies
void main( ) of baseclas in derivedclas
{
derivedclas3 dob3;
dob3.derivedclas1::x = 10; // Scope resolved, use derivedclas1’s x
dob3.y = 20;
dob3.z = 30;
[Link] = dob3.derivedclas1::x+dob3.y+dob3.z; //Scope resolved
cout << dob3.derivedclas1::x << “ “ ; //Scope resolved
cout << dob3.y << “ “ << dob3.z << “ “ << [Link] ;
getch( );
}
In the above program, as we have used :: , the program has manually selected
derivedclas1’s version of baseclas.
The above program can also be write by using the keyword virtual as shown below.
class baseclas
{
public: int x;
};
class derivedclas1 : virtual public baseclas // derivedclas1 inherits baseclas as virtual
{
public: int y;
};
class derivedclas2 : virtual public baseclas // derivedclas2 inherits baseclas as virtual
{
public: int z;
};
class derivedclas3 : public derivedclas1, public derivedclas2
{
public: int total; // derivedclas3 inherits both derivedclas1
}; and derivedclas2. So there are two copies
void main( ) of baseclas in derivedclas
{
derivedclas3 dob3;
dob3.x = 10; // No ambiguity here
dob3.y = 20;
dob3.z = 30;
[Link] = dob3.x+dob3.y+dob3.z; // No ambiguity here
cout << dob3.x << “ “ ; // No ambiguity here
cout << dob3.y << “ “ << dob3.z << “ “ << [Link] ;
getch( );
}
In the above program, as we have used the keyword virtual in class derivedclas1 and
derivedclas2, the program has automatically selects any one of baseclas.