10.3 Overloading Unary Operators
10.5 Constraint on Increment and Decrement Operators
10.6 Overloading Binary Operators
10.7 Overloading with friend Function
10.8 Overloading Assignment Operator (=)
10.10 Rules for Overloading Operators
10.11 One-Argument Constructor and Operator Function
Operator overloading is one of the important and useful features of C++. We are familiar with function overloading in which multiple functions use the same name. The concept of operator overloading is somewhat similar to that of function overloading.
A symbol that is used to perform an operation is called an operator. It is used to perform an operation with constants and variables. A programmer cannot build an expression without an operator.
C++ frequently uses user-defined data types that are a combination of one or more basic data types. C++ has the facility to create/build user-defined data type. User-defined data types created from class or struct are nothing but a combination of one or more variables of basic data types. The compiler knows how to perform various operations using operators for the built-in types; however, for the objects those are instance of the class, the operation routine must be defined by the programmer.
For example, in traditional programming languages the operators such as +, −, <=, >=, etc. can be used only with basic data types such as int or float. The operator + (plus) can be used to perform addition of two variables, but the same is not applicable for objects. The compiler cannot perform addition of two objects. The compiler would throw an error if addition of two objects is carried out. The compiler must be made aware of the addition process of two objects. When an expression including operation with objects is encountered, a compiler searches for the definition of the operator, in which a code is written to perform an operation with two objects. Thus, to perform an operation with objects we need to redefine the definition of various operators. For example, for addition of objects A and B, we need to define operator + (plus). Redefining the operator plus does not change its natural meaning. It can be used for both variables of built-in data type and objects of user-defined data type.
Operator overloading is one of the most valuable concepts introduced by C++ language. It is a type of polymorphism. Polymorphism permits to write multiple definitions for functions and operators. C++ has a number of standard data types such as int, float, char, etc. The operators +, −, *, and = are used to carry operations with these data types. Operator overloading helps the programmer to use these operators with the objects of classes. The outcome of operator overloading is that the objects can be used in as natural manner as the variables of basic data type. Operator overloading provides the capability to redefine the language in which the working operator can be changed.
Consider an example,
a=c+d;
c=a-d;
where, a, c, and d are variables of basic data types like int or float. The use of operator +, −, and = is valid. However, if we try these operators with the object, the compiler displays an error message “Illegal structure operation.”
class number
{
public:
int x;
int y;
};
For example, A, B, and C are three objects of class number. Each object holds an individual copy of member variable x and y. We want to perform addition of A and B and store the result in C. For the sake of understanding, the member variables are declared in public section. The addition of A and B implies addition of member variables of A and member variables of B. The result of this operation will be stored in member variables of C. This feature can be implemented as follows
10.1 Write a program to perform addition of two objects and store the result in third object. Display contents of all the three objects.
#include<iostream.h>
#include<constream.h>
class number
{
public:
int x;
int y;
number() { } // ZERO ARGUMENT CONSTRUCTOR
number (int j, int k ) // TWO ARGUMENT CONSTRUCTOR
{
x=j;
y=k;
}
void show()
{
cout<<“ x=”<<x<<“y=”<<y;
}
};
void main()
{
clrscr();
number A(2,3),B(4,5),C;
A.show();
B.show();
C.x=A.x+B.x; // ADDITION OF TWO OBJECTS
C.y=A.y+B.y; // USING MEMBER VARIABLES DIRECTLY
C.show();
}
OUTPUT
x=2 y=3
x=4 y=5
x=6 y=8
Explanation: In the above program, A, B, and C are objects of class number. Using constructor, objects are initialized. Consider the following statements:
C.x=A.x+B.x;
C.y=A.y+B.y;
In the above statements, addition of members of objects A and B is performed and stored in C. Each member variable is accessed individually and stored in member variable of C. For example, member x of A and member x of B are added and stored in x of C. Similarly, addition of the other members is carried out.
In this program we cannot perform operation C=A+B. The operation with objects is complicated because it involves operation of one or more data member variables which are part of objects.
OPERATOR OVERLOADING
The capability to relate the existing operator with a member function and use the resulting operator with objects of its class as its operands is called operator overloading.
The keyword operator defines a new action or operation to the operator.
Syntax:
Return type Operator operator symbol (parameters)
{
statement1;
statement2;
}
The keyword “operator”, followed by an operator symbol, defines a new (overloaded) action of the given operator.
Example:
number operator + (number D)
{
number T;
T.x=x+D.x;
T.y=y+D.y;
return T;
}
Overloaded operators are redefined within a C++ class using the keyword operator followed by an operator symbol. When an operator is overloaded, the produced symbol is called the operator function name. The above declarations provide an extra meaning to the operator. Operator functions should be either member functions or friend functions. A friend function requires one argument for unary operators and two for binary operators, while a member function requires one argument for binary operators and no argument for unary operator. When the member function is called, the calling object is passed implicitly to the function and hence available for member function. While using friend functions, it is essential to pass the objects by value or reference. The prototype of operator functions in classes can be written as follows.
Operator overloading can be carried out in the following steps.
10.2 Write a program to perform addition of two objects using operator keyword.
#include<iostream.h>
#include<constream.h>
class number
{
public:
int x;
int y;
number() { } // ZERO ARGUMENT CONSTRUCTOR
number (int j, int k ) // TWO ARGUMENT CONSTRUCTOR
{
x=j;
y=k;
}
number operator + ( number D)
{
number T;
T.x=x+D.x;
T.y=y+D.y;
return T;
} void show()
{
cout<<“ x=”<<x<<“y=”<<y;
}
};
void main()
{
clrscr();
A.show();
B.show();
C=A+B;
C.show();
}
OUTPUT
x=2 y=3
x=4 y=5
x=6 y=8
Explanation: In the above program A, B, and C are objects of class number. Here, we performed the addition using statement C=A+B. Remember, in the last program we were not able to execute this statement. Instead of this, two separate statements were used to perform addition.
In this program, the statements that perform addition operation of each individual member of objects are written in function operator. The operator has return type and single argument. It also uses a local object (T) to hold addition as long as the operator function is active. Whenever the statement C=A+B is executed, the compiler searches for definition of operator +. The object A invokes the operator function and object B is passed as argument. The copy of object B is stored in the formal argument D. The member variables of A are directly available in operator function as the function is invoked by the same object. The addition of individual members are carried out and stored in member variable of object T. The return type of operator function is same as that of its class. The function returns object T and it is assigned to variable C.
Overloading devoid of explicit argument to an operator function is called unary operator overloading. The operators ++, −−, and − are unary operators. The unary operators ++ and −− can be used as prefix or suffix with the functions. These operators have only single operand. The following examples illustrate the overloading of unary operators.
10.3 Write a program to increment member variables of object. Overload unary ++ operator.
#include<iostream.h>
#include<constream.h>
class num
{
private:
int a,b,c,d;
public :
num ( int j, int k, int m, int l)
{
b=k;
c=m;
d=l;
}
void show(void);
void operator ++();
};
void num :: show()
{
cout<<“A=”<<a<<“B=” <<b<<“C=”<<c<<“D=”<<d;
}
void num :: operator ++()
{
++a; ++b; ++c; ++d;
}
main()
{
clrscr();
num X(3,2,5,7);
cout<<“ Before Increment of X:”;
X.show();
++X;
cout<<“ After Increment of X:”;
X.show();
return 0;
}
OUTPUT
Before Increment of X : A= 3 B= 2 C = 5 D = 7
After Increment of X : A= 4 B= 3 C = 6 D = 8
Explanation: In the above example the class num contains four integer variables a, b, c, and d. The class also has two-member functions show() and operator ++() and one parameterized constructor. The constructor is used to initialize object. The show() displays the contents of the member variables. The operator ++() overloads the unary operator ++. When this operator is used with integer or float variables, its value is increased by one. In this function, ++ operator precedes each member variable of class. This operation increments the value of each variable by one.
In function main(), the statement ++X calls the function operator ++(), where X is an object of the class num. The function can also be called using statement X. operator ++(). In the output, values of member variables before and after increment operations are displayed.
10.4 Write a program to overload – operator.
#include<iostream.h>
#include<conio.h>
class num
{
private:
int a,b,c,d;
public :
num ( int x, int y, int z, int w)
{
a=x;
b=y;
c=z;
d=w;
}
void show(void);
void operator -();
}; void num :: show()
{
cout<<“A=”<<a<<“B=” <<b<<“C=”<<c<<“D=”<<d;
}
void num :: operator -()
{
a=-a;
b=-b;
c=-c;
d=-d;
} main()
{
clrscr();
num X(2,2,8,4);
cout<<“ Before Negation of X:”;
X.show();
-X;
cout<<“ After Negation X:”;
X.show();
return 0;
}
OUTPUT
Before Negation of X : A= 2 B= 2 C = 8 D = 4
After Negation X : A= -2 B= -2 C = -8 D = -4
Explanation: The above program is same as previous one. Here, the operator – is overloaded. The statement –X calls the function operator –(). The function operator–() makes all the member variables negative. The function show() displays the values of member variables on the screen.
In the last few examples we declared the operator() of void types, that is, it will not return any value. However, it is possible to return value and assign to it other object of the same type. The return value of operator is always of class type, because the operator overloading is only for objects. An operator cannot be overloaded for basic data type. Hence, if the operator returns any value, it will be always of class type. Consider the following program.
10.5 Write a program to return values from operator() function.
#include<iostream.h>
#include<conio.h>
class plusplus
{
private:
int num;
public :
plusplus() { num=0; }
int getnum() { return num;}
plusplus operator ++ (int)
{
plusplus tmp;
num=num+1;
tmp.num=num;
return tmp;
}
};
void main()
{
clrscr();
plusplus p1, p2;
cout<<“ p1=”<<p1.getnum();
cout<<“ p2=”<<p2.getnum();
p1=p2++;
cout<<endl<<“ p1=”<<p1.getnum();
cout<<endl<<“ p2=”<<p2.getnum();
p1++;
// p1++=2;
cout<<endl<<“ p1=”<<p1.getnum();
cout<<endl<<“ p2=”<<p2.getnum();
}
p1 = 0
p2 = 0
p1 = 1
p2 = 1
p1 = 2
p2 = 1
Explanation: In the above program class plusplus is declared with one private integer num. The class constructor initializes the object with zero. The member function getnum() returns current value of variable num. The operator ++() is overloaded and it can handle as postfix increment of the objects. In case of an increase in the prefix it will flag an error.
The p1 and p2 are objects of the class plusplus. The statement p1=p2++ first increments the value of p2 and then assigns it to the object p1. The values displayed will be one for the objects. The object p1 is increased. This time, the values of object displayed will be two and one.
When an operator (increment/decrement) is used as prefix with object, its value is incremented/decremented before operation, and, on the other hand, the postfix use of operator increments/decrements the value of variable after its use.
When ++ and – operators are overloaded, there exists no difference between the postfix and prefix overloaded operator functions. The system has no way of determining whether the operators are overloaded for postfix or prefix operation. Hence, the operator must be overloaded in such a way that it will work for both prefix and postfix operations. The ++ or −− operator overloaded for prefix operation works for both prefix and postfix operations but with warning message, but vice versa is not possible. To make a distinction between prefix and postfix notations of operator, a new syntax is used to indicate postfix operator overloading function. The syntaxes are as follows.
Operator ++ ( int ) // postfix notation
Operator ++() // prefix notation
The argument followed by operator (++ or −−) should have type ‘int’. When a postfix operator ++ or operator −− is declared, the last parameter must be declared with the type int. No other types such as float, long, etc. are allowed. We can use this operator with all types of variables including float, long, etc. Declaring int does not mean that it is only for integer type. The following program illustrates overloading of ++ operator in postfix and prefix styles.
10.6 Write a program to overload ++ and – operator for prefix and postfix use.
#include<iostream.h>
#include<constream.h>
class number
{
float x;
number ( float k) { x=k; }
void operator ++ (int) // postfix notation
{ x++; }
void operator --() // prefix notation
{ --x; }
void show() { cout<<“ x=”<<x; }
};
void main()
{
clrscr();
number N(2.3);
cout<<“ Before Incrimenting: ”;
N.show();
cout<<“ After Incrimenting: ”;
N++; // postfix increment
N.show();
cout<<“ After Decrementation:”;
--N; // prefix decrement
N.show();
}
OUTPUT
Before incrementing:
x=2.3
After incrementing:
x=3.3
After decrementation:
x=2.3
Explanation: In this program, operator ++ and – are overloaded. The ++ operator is overloaded for postfix use and – operator is overloaded for prefix use. You can see that the keyword (int) is followed by the operator ++, which is necessary for postfix notation of operator. The operator – is overloaded for prefix operation. Here, a value of float member variable is incremented and decremented.
Overloading with a single parameter is called binary operator overloading. Similar to unary operators, binary operators can also be overloaded. Binary operators require two operands, and they are overloaded by using member functions and friend functions.
If overloaded as a member function, binary operators require one argument. The argument contains value of the object, which is to the right of the operator. If we want to perform the addition of two objects o1 and o2, the overloading function should be declared as follows.
Where, num is a class name and o2 is an object.
To call function operator the statement is as follows:
o3=o1+o2;
We learnt that a member function can be called by using class of that object. Hence, the called member function is always preceded by the object. Here, in the above statement, the object o1 invokes the function operator() and the object o2 is used as an argument for the function. The above statement can also be written as follows.
o3=o1.operator +(o2);
Here, the data members of o1 are passed directly and data members of o2 are passed as an argument. While overloading binary operators, the left-hand operand calls the operator function and the right-hand operator is used as argument.
The friend functions can be used alternatively with member functions for overloading of binary operators. The friend function requires two operands to be passed as arguments.
o3=o1+o2;
o3=operator+(o1,o2);
Both the above statements have the same meaning. In the second statement, two objects are passed to the operator function.
The use of member function and friend function produces the same result. friend functions are useful when we require performing an operation with operand of two different types. Consider the statements
X=Y+3;
X=3+Y;
where X and Y are objects of the same type. The first statement is valid. However, the second statement will not work. The first operand must be an object of the same class. This problem can be overcome by using friend function. The friend function can be called without using an object. The friend function can be used with standard data type as left-hand operand and an object as right-hand operand.
The following programs are illustrated based on the above discussion.
10.7 Write a program to overload + binary operator.
#include<iostream.h>
#include<conio.h>
class num
{
private:
public:
void input(void);
void show(void);
num operator+(num);
};
void num :: input()
{
cout<<“ Enter Values for a,b,c and d:”;
cin>>a>> b>>c>>d;
}
void num :: show()
{
cout<<“A=”<<a <<“B=” <<b <<“C=”<<c <<“D=”<<d <<“ ”;
}
num num :: operator +(num t)
{
num tmp;
tmp.a=a+t.a;
tmp.b=b+t.b;
tmp.c=c+t.c;
tmp.d=d+t.d;
return (tmp);
}
main()
{
clrscr();
num X,Y,Z;
cout<<“ Object X”;
X.input();
cout<<“ Object Y”;
Y.input();
Z=X+Y;
cout<<“ X:”;
X.show();
cout<<“Y:”;
Y.show();
cout<<“Z:”;
Z.show();
return 0;
}
OUTPUT
Object X
Enter Values for a,b,c and d : 1 4 2 1
Enter Values for a,b,c and d : 2 5 4 2
X : A= 1 B= 4 C = 2 D = 1
Y : A= 2 B= 5 C = 4 D = 2
Z : A= 3 B= 9 C = 6 D = 3
Explanation: In the above program, binary operator + is overloaded. Using the overloading operator +, addition of member variables of two objects is performed and results are assigned to member variables of third object. In this program X, Y, and Z are objects of class num. The statement Z=X+Y invokes the operator function. In this statement, the object y is assigned to object t of operator function and member variables of X are accessed directly. The object tmp is used for holding the result of addition, and it is returned to object Z after function execution. The function show() displays the values of three objects.
10.8 Write a program to perform multiplication using an integer and object. Use friend function.
#include<iostream.h>
#include<conio.h>
class num
{
private:
int a,b,c,d;
public :
void input(void);
void show(void);
friend num operator * (int, num); // friend function
declaration
};
void num :: input()
{
cout<<“ Enter Values for a,b,c and d:”;
cin>>a>> b>>c>>d;
}
void num :: show()
{
cout<<“A=”<<a<<“B=” <<b<<“C=”<<c<<“D=”<<d <<“ ”;
}
num operator * (int a, num t)
{
num tmp;
tmp.a=a*t.a;
tmp.b=a*t.b;
tmp.c=a*t.c;
return (tmp);
}
main()
{
clrscr();
num X,Z;
cout<<“ Object X”;
X.input();
Z=3*X;
cout<<“ X:”;
X.show();
cout<<“Z:”;
Z.show();
return 0;
}
OUTPUT
Object X
Enter Values for a,b,c and d : 1 2 2 3
X : A= 1 B= 2 C = 2 D = 3
Z : A= 3 B= 6 C = 6 D = 9
Explanation: In the above program, the equation Z=3*X contains integer and class object. We know that the left-hand operand is always used to invoke the function and the right-hand operand is passed as an argument. In such type of equations, member functions are not useful because the left-hand operand is integer and cannot invoke the function. Hence, the function operator *() is declared as friend. The friend function calls the operator *() and carries the multiplication of each member variable by three. The results are displayed in the output.
The friend functions are more useful in operator overloading. They offer better flexibility, which is not provided by the member function of the class. The difference between member function and friend function is that the member function takes argument explicitly. On the contrary, the friend function needs the parameters to be explicitly passed. The syntax of operator overloading with friend function is as follows:
friend return-type operator operator-symbol (variable1, variable2)
{
statement1;
statement2;
}
The keyword friend precedes function prototype declaration. It must be written inside the class. The function can be defined inside or outside the class. The arguments used in friend function are generally objects of the friend classes. A friend function is similar to normal function; the only difference being that friend function can access private member of the class through the objects. friend function has no permission to access private members of a class directly. However, it can access the private members through objects of the same class.
10.9 Write a program to overload unary operator using friend function.
#include<iostream.h>
#include<constream.h>
class complex
{
float real,imag;
public:
complex() // zero argument constructor
{
real=imag=0;
}
complex (float r, float i) // two argument constructor
{
real=r;
imag=i;
}
friend complex operator - ( complex c)
{
c.real=-c.real;
c.imag=-c.imag;
return c;
}
void display()
{
cout<<“ Real:”<<real;
cout<<“ Imag:”<<imag;
}
};
void main()
{
clrscr();
complex c1(1.5,2.5),c2;
c1.display();
c2=-c1;
cout<<“ After Negation ”;
c2.display();
}
Real : 1.5
Imag : 2.5
After Negation
Real : -1.5
Imag : -2.5
Explanation: In the above program, operator – is overloaded using friend function. The operator function is defined as friend. The statement c2=−c1 invokes the operator function. This statement also returns the negated values of c1 without affecting actual value of c1 and assigns it to object c2.
The negation operation can also be used with an object to alter its own data member variables. In such a case, the object itself acts as a source and destination object. This can be accomplished by sending reference of object. The following program illustrates this.
10.10 Write a program to pass reference of an object to operator function.
#include<iostream.h>
#include<constream.h>
class complex
{
float real,imag;
public:
complex (float r, float i) // two argument constructor
{
real=r;
imag=i;
}
friend void operator - ( complex & c)
{
c.real=-c.real;
c.imag=-c.imag;
}
void display()
{
cout<<“ Real:”<<real;
cout<<“ Imag:”<<imag;
}
};
void main()
{
clrscr();
complex c1(1.5,2.5);
c1.display();
cout<<“ After Negation ”;
c1.display();
}
OUTPUT
Real : 1.5
Imag : 2.5
After Negation
Real : -1.5
Imag : -2.5
Explanation: In the above program, the object c1 itself acts as a source and destination object. The reference of object is passed to operator function. The object c is a reference object of c1. The values of object c are replaced by itself by applying negation.
In this section, data members of one object are initialized with some values, and the same values are assigned to another object with assignment operator. Assignment operator can be overloaded by two ways:
Following program demonstrates overloading of assignment (=) operator implicitly:
10.11 Program to overload the assignment operator (=) implicitly.
#include<iostream.h>
#include<conio.h>
class num
{
private:
int x;
public:
num(int a);
void show();
};
int main()
{
clrscr();
num a1(2),a2(8);
cout<<“ Before overloading assignment operator:”;
cout<<“ A=”;
cout<<“ B=”;
a2.show();
a2=a1; //Implicit overloading assignment operator
cout<<“ After overloading assignment operator implicitly(b=a):”;
cout<<“ A=”;
a1.show();
cout<<“ B=”;
a2.show();
return 0;
}
num::num(int a)
{
x=a;
}
void num::show()
{
cout<<x<< “ ”;
}
OUTPUT
Before overloading assignment operator:
A = 2
B = 8
After overloading assignment operator implicitly(b=a):
A = 2
B = 2
Following program demonstrates overloading of assignment (=) operator explicitly:
10.12 Program to overload the assignment operator (=) explicitly.
#include<iostream.h>
#include<conio.h>
class num
{
private:
int x;
public:
num(int a);
void operator = (num b);
void show();
};
{
clrscr();
num a1(100),a2(200);
cout<<“ Before overloading assignment operator:”;
cout<<“ A=”;
a1.show();
cout<<“ B=”;
a2.show();
cout<<“ After overloading assignment operator Explicitly:”;
a2.operator=(a1);
cout<<“ A=”;
a1.show();
cout<<“ B=”;
a2.show();
return 0;
}
num::num(int a)
{
x=a;
}
void num::show()
{
cout<<x<< “ ”;
}
void num::operator = (num b)
{
x=b.x;
}
OUTPUT
Before overloading assignment operator:
A = 100
B = 200
After overloading assignment operator Explicitly:
A = 100
B = 100
We learnt that when constants and variables of various data types are clubbed in a single expression, automatic type conversion takes place. This is so for basic data types. The compiler is unknown about the user-defined data type and about their conversion to other data types. The programmer should write the routines that convert basic data type to user-defined data type or vice versa. There are three possibilities of data conversion as given below:
The conversion from basic to class type is easily carried out. It is automatically done by the compiler with the help of in-built routines or by applying type casting. In this type, the left-hand operand of = sign is always class type and the right-hand operand is always basic type. The below-given program explains the conversion from basic to class type.
10.13 Write a program to define constructor with no argument and with float argument. Explain how compiler invokes constructor depending on data type.
#include<iostream.h>
#include<conio.h>
class data
{
int x;
float f;
public :
data()
{
x=0;
f=0;
}
data ( float m)
{
x=2;
f=m;
}
void show()
{
cout<<“ x= ”<<x<<“ f=”<<f;
cout<<“ x= ”<<x<<“f=”<<f;
}
};
int main()
{
clrscr();
data z;
z=1;
z.show();
z.show();
return 0;
}
OUTPUT
x= 2 f = 1
x= 2 f = 1
x= 2 f = 2.5
x= 2 f = 2.5
Explanation: In the above program, the class data has two member variables each of integer and float types respectively. It also has two constructors one with no argument and the other with float argument. The member function show() displays the contents of the data members. In function main(), z is an object of class data. When z is created, the constructor with no argument is called and data members are initialized to zero. When z is initialized to one, the constructor with float argument is invoked. The integer value is converted to float type and assigned member variable f. Again when z is assigned to 2.5, same process is repeated. Thus, the conversion from basic to class type is carried out.
In the previous example, we studied how compiler makes conversion from basic to class type. The compiler does not have any knowledge about the user-defined data type built using classes. In this type of conversion, the programmer needs to explicitly tell the compiler how to perform conversion from class to basic type. These instructions are written in a member function. Such type of conversion is also known as overloading of type cast operators. The compiler first searches for the operator keyword followed by data type and if it is not defined, it applies the conversion functions. In this type, the left-hand operand is always of basic data type and the right-hand operand is always of class type. During this conversion, the statement should satisfy the following conditions:
10.14 Write a program to convert class type data to basic type data.
#include<iostream.h>
#include<conio.h>
class data
{
int x;
float f;
data()
{
x=0;
f=0;
}
operator int()
{
return (x);
}
operator float()
{ return f; }
data ( float m)
{
x=2;
f=m;
}
void show()
{
cout<<“ x= ”<<x<<“f=”<<f;
cout<<“ x= ”<<x<<“f=”<<f;
}
};
int main()
{
clrscr();
int j;
float f;
data a;
a=5.5;
j=a; // operator int() is executed
f=a; // operator float() is executed
cout<<“ Value of j :”<<j;
cout<<“ Value of f :”<<f;
return 0;
}
OUTPUT
Value of j : 2
Value of f : 5.5
Explanation: In the above program, the class data has two member variables each of integer and float data type. It also contains constructors as per described in the last example. In addition, it contains overloaded data types int and float. These functions are useful for conversion of data from class type to basic type. Consider the following statements:
In the first statement object a is assigned to integer variable j. We know that class type data is a combination of one or more basic data types. The class contains two member functions operator int() and operator float(). Both these function are able to convert data types from class to basic. In statement (a), variable j is of integer type, the function operator int() is invoked and integer value data member is returned. In statement (b), f is of float type, the member function operator float() is invoked.
We learnt how to convert basic data type to class type and vice versa. Now the third method is conversion from class type to another class type. When an object of one class is assigned to object of another class, it is necessary to give clear-cut instructions to the compiler about how to make conversion between these two user-defined data types. The method must be instructed to the compiler. There are two ways to convert object data type from one class to another. One is to define a conversion operator function in source class or a one-argument constructor in a destination class. Consider the following example:
X=A;
Here, X is an object of class XYZ and A is an object of class ABC. The class ABC data type is converted to class XYZ. The conversion happens from class ABC to XYZ. The ABC is a source class and XYZ is a destination class.
We know the operator function operator data-type(). Here, data type may be built-in data type or user-defined data type. In the above declaration, the data type indicates target type of object. Here, the conversion takes place from class ABC (source class) to class XYZ (destination class).
10.15 Write a program to convert integer to date and vice versa using conversion function in source class.
#include<iostream.h>
#include<stdlib.h>
#include<string.h>
#include<conio.h>
class date
{
char d[10];
public:
date() { d[0]=NULL; }
date (char *e) { strcpy(d,e); }
void show() { cout<<d; }
};
{
int mt,dy,yr;
public:
dmy() { mt=dy=yr=0; }
dmy (int m, int d, int y)
{
mt=m;
dy=d;
yr=y;
}
operator date()
{
char tmp[3],dt[9];
itoa(dy,dt,10);
strcat(dt,”-”);
itoa(mt,tmp,10);
strcat(dt,tmp);
strcat(dt,”-”);
itoa(yr,tmp,10);
strcat(dt,tmp);
return (date(dt));
}
void show()
{
cout<<dy<<“ ”<<mt<<“ ”<<yr;
}
};
int main()
{
clrscr();
date D1;
dmy D2(1,7,99);
D1=D2;
cout<<endl<<“D1=”;
D1.show();
cout<<endl<<“D2=”;
D2.show();
return 0;
}
OUTPUT
D1=7-1-99
D2=7 1 99
Explanation: In the above program, date and dmy are two classes declared. In function main(), D1 is an object of class date and D2 is an object of class dmy. The object D2 is initialized.
The statement D1=D2 initializes D1 with D2. Here, both the objects D1 and D2 are of different types hence the conversion function date() is called to perform the conversion from one object to another object.
10.16 Write a program to convert integer to date and vice versa using conversion function in destination class.
#include<iostream.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
class dmy
{
int d,m,y;
public:
dmy() { d=m=y=0; }
dmy (int da, int ma, int ya) { d=da; m=ma; y=ya; }
int day() { return (d); }
int month() { return (m); }
int year() { return (y); }
void show() { cout<<d<<“ ”<<m<<“ ”<<y; }
};
class date
{
private :
char dts[9];
public :
date() { dts[0]=0; }
date ( char *e) { strcpy (dts,e); }
void show() { cout<<dts; }
date ( dmy k)
{
int d=k.day(); // first member function
int m=k.month(); // second member function
int y=k.year(); // third member function
char tmp[3];
itoa(d,dts,10);
strcat(dts,”-”);
itoa(m,tmp,10);
strcat(dts,tmp);
strcat(dts,”-”);
strcat(dts,tmp);
}
};
int main()
{
clrscr();
date D1;
dmy D2(1,3,77);
D1=D2;
cout<<endl<<“D1=”;
D1.show();
cout<<endl<<“D2=”;
D2.show();
return 0;
}
OUTPUT
D1=1-3-77
D2=1 3 77
Explanation: In the above program, as soon as the statement D1=D2 is executed, the one-argument constructor defined in the class date is invoked. The one-argument constructor carries the conversion. The constructor calls three-member function of dmy class to get the day, month, and year of the date. Here, in this program conversion is done by using the constructor in destination object.
10.17 Write a program to convert class data type to another class data type.
#include<iostream.h>
#include<conio.h>
class minutes
{
int m;
public:
minutes()
{ m=240; }
get()
{ return (m);}
void show()
{ cout<<“ Minutes=”<<m; }
};
class hours
int h;
public:
void operator = (minutes x);
void show()
{ cout<<“ Hours=”<<h; }
};
void hours:: operator = (minutes x)
{
h=x.get()/60;
}
int main()
{
clrscr();
minutes minute;
hours hour;
hour=minute;
minute.show();
hour.show();
return 0;
}
OUTPUT
Minutes = 240
Hours = 4
Explanation: In the above program two classes are declared. The class minutes has one integer member variable m and two member functions get() and show(). It also contains constructor without argument. The class hours has one integer member variable and show() member function. The class hours contain overloaded operator function. In function main(), minute is an object of class minutes and hour is an object of class hours. The program converts minutes to hours. The equation hour=minute invokes the operator function. In function operator(), x is an object of class minutes. The object x invokes the member function get() that returns total number of minutes. Number of hours is obtained by dividing the total number of minutes by 60. The equation h=x.get()/60 performs this task and assigns result to h. Thus, the result of the program is as per given above.
A+=B;
assigns addition of objects A and B to A. The overloaded operator must carry the same task like original operator according to the language. The following statement must perform the same operation like last statement:
A=A+B;
10.18 Misuse of operator overloading. Perform subtraction using + operator.
#include<iostream.h>
#include<constream.h>
class num
{
int x;
public:
num() { x=0; }
num ( int k) { x=k; }
num operator + ( num n)
{
num s;
s.x=x-n.x;
return s;
}
void show() { cout<<“ x=”<<x; }
};
void main()
{
clrscr();
num a(10), b(5),c;
c=a+b;
c.show();
}
OUTPUT
X=5
Explanation: In the above program, the operator + is overloaded. It performs subtraction. Such type of misuse must be avoided while overloading operators. The programmer thought that it would perform addition, but in reality it performs subtraction.
Table 10.1 Non-overloadable Operators
Operator |
Description |
---|---|
. |
Member operator |
.* |
Pointer to member operator |
:: |
Scope access operator |
?: |
Conditional operator |
sizeof() |
Size of operator |
# and ## |
Preprocessor symbols |
For example, operators such as ?:, ::, and .* are combinations of more than one symbol. The condition operator needs three arguments. It is only one operator that requires three arguments. Hence, the above operators cannot be overloaded.
Table 10.2 Non-overloadable Operators with friend Function
Operator |
Description |
---|---|
() |
Function call delimiter/operator |
= |
Assignment operator |
[] |
Subscripting operator |
-> |
Class member access operator |
We studied that a single-argument constructor or an operator function could be used for conversion of objects of different classes. A large range of classes as class libraries are available with the compiler; however, they are linked with the main program. Their source code is invisible to us. Only object of these classes can be used. The user cannot change the in-built classes. The problem occurs when a programmer attempts conversion from object of class declared by him/her to type of in-built class. This problem can be avoided by defining conversion routine in the user-defined class. The conversion routine may be single-argument constructor or an operator function. It depends on whether the object is a source or destination. Table 10.3 describes conversion type and place of routine to be defined, followed by description.
Table 10.3 Conversion Types
Defining multiple conversion routines puts the complier in an uncertain condition. The compiler fails to select appropriate conversion routines. For example, if one argument constructor is present in destination class and operator function in source class, the complier cannot select appropriate routines. Hence, while defining conversion routines, follow the conditions given in Table 10.3.
The predefined objects cin and cout are used to perform various input/output operations in C++. The extraction operator (>>) is used with cin object to carry out input operations. The insertion operator (<<) is used with cout object to carry out output operations. In Chapter 2 we learnt how to create objects similar to cin and cout. It is also possible to overload both these extraction and insertion operators with friend function.
The syntax for overloading (<<) insertion operator is as follows:
friend ostream & operator << ( ostream & put, v1)
{
// code
return put;
}
The keyword friend precedes the declaration. The ostream is an output stream class followed by reference and keyword operator. The put is an output stream object like cout. The v1 is a user-defined class object. The following program explains overloading of insertion operator with friend function.
10.19 Write a program to overload insertion operator (<<) with friend function.
#include<iostream.h>
#include<constream.h>
class string
{
char *s;
public:
string ( char *k)
{
s=k;
}
friend ostream & operator << (ostream &put, string & k)
{
put <<k.s;
return put;
}
};
int main()
{
clrscr();
string s(“INDIA”);
cout<<s;
return 0;
}
OUTPUT
INDIA
Explanation: In the above program the insertion operator << is overloaded with friend function. The overloaded operator allows us to display contents of object directly using cout statement. The statement cout<<s; displays contents of object s on the screen.
Similarly, extraction operator can be overloaded. The syntax for overloading extraction operator is as follows:
friend istream & operator >> ( istream & get, v2)
{
// code
return get;
}
The following program explains overloading of extraction operator.
10.20 Write a program to overload extraction operator using friend function.
#include<iostream.h>
#include<constream.h>
class string
{
char *s;
public:
friend istream & operator >> (istream &get, string & k)
{
cout<<“ Enter a string :”;
get >>k.s;
return get;
}
};
int main()
{
clrscr();
string s;
cin>>s; // input string
return 0;
}
OUTPUT
BEST LUCK
Explanation: This program is same as the previous one. Here, extraction operator is overloaded. The object s is directly used with cin statement. After execution of this statement, the overloaded operator is invoked.
10.21 Write a program to overload > operator.
#include<iostream.h>
#include<conio.h>
class A
{
int a;
public:
int operator > (A);
void inA ( )
{
cin>>a;
}
void outA() { cout<<“ Largest Number=”<<a;}
};
int A ::operator > (A l)
{
if (a>l.a)
return 1;
else
return 0;
}
int main()
{
clrscr();
A J,K;
J.inA();
K.inA();
if (J>K) J.outA();
else K.outA();
return 0;
}
OUTPUT
Enter a number : 9
Enter a number : 4
Largest Number = 9
Explanation: In the above program, class A has one integer type data member and inA() and outA() are member functions. The function inA() is used to read an integer through the keyboard and outA() is used to display the contents of data variable on the screen. The operator > is overloaded. The comparison of explicit (K) and implicit (J) arguments is performed by the if statement. If J is greater, one is returned otherwise zero. If the return value is one, that is, J is greater in function main(), if block is executed otherwise else block is executed.
10.22 Write a program to overload ! = Operator.
#include<iostream.h>
#include<conio.h>
class A
{
int a;
public:
void inA ( )
{ cout<<“ Enter a number:”;
cin>>a;
}
void m1() { cout<<“ Both numbers are same ”; }
void m2() { cout<<“ Both numbers are different ”; }
};
int A ::operator != (A l)
{
if (a!=l.a)
return 0;
else
return 1;
}
int main()
{
clrscr();
A J,K;
J.inA();
K.inA();
if (J!=K) J.m1();
else K.m2();
return 0;
}
OUTPUT
Enter a number : 4
Enter a number : 4
Both numbers are same
Explanation: The above program is same as the previous one. The only difference is that (! =) not equal to operator is overloaded.
10.23 Write a program to overload & operator. When this operator is used with the object, the program should prompt for inputting a number.
#include<iostream.h>
#include<conio.h>
class A
{
int a;
public:
void inA ( )
{ cout<<“ Enter a number:”;
cin>>a;
}
void outA()
{
cout<<“ a=”<<a;
}
};
A A :: operator & (A l)
{
cout<<“ Enter Two Numbers:”;
cin>>a>>l.a;
return (l);
}
int main()
{
clrscr();
A J,K;
K=J&K;
J.outA();
K.outA();
return 0;
}
OUTPUT
Enter Two Numbers : 8 9
a = 8
a = 9
Explanation: In the above program the operator & is overloaded. J and K are objects of class A. The equation K=J&K calls the overloaded operator. The overloaded function reads integer and assigns to member variables of objects J and K. The return value is assigned to object K. The outA() function displays the contents of member variable of calling object.
10.24 Write a program to overload < and > operator.
#include<iostream.h>
#include<conio.h>
class A
{
int a;
public:
void operator <(A);
};
A A ::operator > (A l)
{
cout<<“ Enter Two Numbers:”;
cin>>a>>l.a;
return (l);
}
void A :: operator < ( A l)
{
cout<<“ Entered Numbers are:”<<l.a<<“ ”<<a;
}
int main()
{
clrscr();
A J,K;
K=J>J; // Reads numbers
K<J; // Prints numbers
return 0;
}
OUTPUT
Enter Two Numbers : 45 98
Entered Numbers are : 45 98
Explanation: In the above program the operator < and > are overloaded. The > operator is used for reading numbers and < is used for displaying numbers. The output of the program is shown above.
10.25 Write a program to add and multiply two complex objects. Use operator overloading.
#include<iostream.h>
#include<conio.h>
class complex
{
public:
double real, imag;
};
complex setdata(double rr, double ii );
void show (complex cc);
complex operator + ( complex ca, complex cb);
complex operator * (complex ca, complex cb);
{
clrscr();
complex H,I,J,K;
H=setdata(1.3,1.7);
I=setdata(2.2,2.2);
J=H+I;
K=H*I;
cout<<endl<<“H=”;
show (H);
cout<<endl<<“I=”;
show (I);
cout<<endl<<“J=”;
show (J);
cout<<endl<<“K=”;
show(K);
}
complex setdata (double rr, double ii)
{
complex tmp;
tmp.real=rr;
tmp.imag=ii;
return tmp;
}
void show (complex s)
{
cout<<“[“<<s.real<<’,’<<s.imag<<”]”;
}
complex operator + ( complex ca, complex cb)
{
complex tmp;
tmp.real=ca.real+cb.real;
tmp.imag=ca.imag+cb.imag;
return tmp;
}
complex operator * (complex ca,complex cb)
{
complex tmp;
tmp.real=ca.real*cb.real;
tmp.imag=ca.imag*cb.imag;
return tmp;
}
Explanation: In the above program, the complex class has two data members of double data types. They are real and imaginary. The function setdata() is used to set values of class members. The function show() displays the contents of the object on the screen. The operators + and * are overloaded and defined two add and multiply two complex objects. In function main(), H, I, J, and K are four objects of the class complex. The objects H and I are initialized using the setdata() function. The statements J=H+I and K=H*I do the addition and multiplication of two objects by using the overloaded operator. The show() function displays the contents of object.
10.26 Write a program to declare matrix class and perform addition of matrix class objects..
#include<iostream.h>
#include<conio.h>
#include<iomanip.h>
class matrix
{
public:
int num[3][3];
};
matrix operator + ( matrix a, matrix b);
void show (matrix r);
void main()
{
clrscr();
matrix x= { 3,2,5,
1,2,4,
4,7,8 };
matrix y= { 4,7,4,
2,1,4,
3,2,1 };
matrix z;
z=x+y;
show (x);
show(y);
show(z);
}
matrix operator + ( matrix x, matrix y)
{
matrix l;
int i,j;
for (i=0;i<3;i++)
{
for (j=0;j<3;j++)
l.num[i][j]=x.num[i][j]+y.num[i][j];
return l;
}
void show (matrix g)
{
int i,j;
cout<<endl;
for (i=0;i<3;i++)
{
cout<<endl;
for (j=0;j<3;j++)
cout<<setw(8)<<g.num[i][j];
}
}
OUTPUT
3 2 5
1 2 4
4 7 8
4 7 4
2 1 4
3 2 1
7 9 9
3 3 8
7 9 9
Explanation: In the above program, the class matrix has one array element num [3][3]. The objects x, y, and z are of matrix type. The objects x and y are initialized. The addition (+) operator is overloaded and it performs addition of elements of two matrix objects and assigns the sum to the third object. The function show() display the contents of the objects. The statement z=x+y executes the overloaded operator.
10.27 Write a program to overload ++ operator in postfix style.
#include<iostream.h>
#include<conio.h>
class postfix
{
private :
int c;
public :
postfix() { c =0; }
postfix (int g) { c =g; }
postfix operator ++() { return postfix(++c); }
postfix operator ++ (int) { return postfix(c++);}
void show() { cout<<c; }
};
void main()
{
clrscr();
postfix A,B,C;
B=A++;
cout<<endl<<“B=”;
B.show();
cout<<endl<<“A=”;
A.show();
C=++A;
cout<<endl<<“C=”;
C.show();
}
OUTPUT
B=0
A=1
C=2
Explanation: In the above program, the operator ++ is overloaded in suffix and postfix fashion. The difference in the two declaration statements of overloaded operator is the int in the parenthesis in second statement. It tells the compiler to make postfix version of operator (++). In function main(), objects A, B, and C are of postfix type. The objects A, B, and C are initialized to zero by the constructor.
The statement B=A++ assigns value of A to B and then increments object A. The value displayed for B is zero and A is one. The statement C=++A increments object A first and then assigns the value to C. The value of A before increment is one. The value displayed for C is two. The function show() is used to display the contents of the object.
10.28 Write a program to convert text to integer and integer to text.
#include<iostream.h>
#include<stdlib.h>
#include<string.h>
#include<conio.h>
class text
{
private :
char txt[20];
public :
text() { txt[0]=NULL; }
text (char *t ) { strcpy (txt,t); }
text (int d) { itoa(d,txt,10); }
void show() { cout<<txt; }
operator int();
};
text::operator int()
{
int m,tt=0,g=1;
m=strlen(txt)-1;
while (m>=0)
{
tt=tt+(txt[m]-48)*g;
m--;
g*=10;
}
return (tt);
}
void main()
{
clrscr();
text t1=457;
cout<<endl<<“t1=”;
t1.show();
t1=111;
cout<<endl<<“t1=”;
t1.show();
text t2(“325”);
int j=int(t2);
cout<<endl<<“j =”<<j;
text t3(“254”);
j=t3;
cout<<endl<<“j =”<<j;
}
OUTPUT
t1=457
t1=111
j =325
j =254
Explanation: In the above program, constructor with one argument converts the integer to text (user-defined data type). The constructor is executed when an object of text class is created with one parameter. The itoa() function converts integer value to string. For conversion of text to integer, overloaded case operator is used. This operator revives object of text class and converts it to the integer type value.
10.29 Write a program to convert square to square root and vice versa.
#include<iostream.h>
#include<conio.h>
#include<math.h>
class square
{
int s;
public:
get() { return s; }
square (int j) { s=j;}
void show() { cout<<“ Square=”<<s; }
};
class root
{
float r;
public:
root (int k) { r=k; }
operator square ( )
{
return r*r;
}
root (square k)
{
r=sqrt(k.get());
}
void show() { cout<<“ Square Root=”<<r; }
};
void main()
{
clrscr();
square s(81);
root r(0);
r=s; // root = square
r.show();
s.show();
r=10; // invokes constructor
s=r; // square = root
r.show();
s.show();
}
Square Root=9
Square=81
Square Root=10
Square=100
Explanation: In the above program two classes square and root are defined. The conversion routines are defined in class root. The statement r=s; uses one-argument constructor for conversion, and the statement s=r; invokes the operator function for conversion.
Conversion from basic data type to user-defined data type (class type) – the conversion from basic to class type is easily carried out. It is automatically done by the compiler with the help in-built routines or by applying type casting.
Conversion from class type to basic data type – the compiler does not have any knowledge about the user-defined data type built using classes. In this type of conversion, the programmer needs to explicitly tell the compiler how to perform conversion from class to basic type. These instructions are written in a member function. Such type of conversion is also known as overloading of type cast operators.
Conversion from one class type to another class type – when an object of one class is assigned to object of another class, it is necessary to give clear-cut instructions to the compiler about how to make conversion between these two user-defined data types. Using constructor or conversion this function can be performed.
(A) Answer the following questions
(B) Answer the following by selecting the appropriate option
(C) Attempt the following programs
(D) Find the bugs in the following programs
class num
{ int x;
public:
num ( int k) { x=k; }
int operator + ( num n)
{ num s(0);
s.x=x-n.x;
return x;
}
};
void main()
{ num a(1), b(5),c(0);
c=a+b; }
struct num
{ int x;
num ( int k) { x=k; }
void operator ++ ( )
{ ++x; }
};
void main()
{
num b(2);
b++;
cout<<b.x;
}