Lab Sheet 5
Understanding the Concept of Friend Function/Class and Operator Overloading
1. Friend Function and Class
In some cases, we need to access the private data members of a class from non-member functions. In such situations, we must declare such a function as a friend function of the class. This type of friend function seems to violate the data hiding feature of OOP. However, with the friend functions mechanism, data integrity is still maintained. The creator of the class declares which functions are friends of it, but the functions cannot declare themselves as friends of a class.
Sometimes we may need to make one or all the member functions of a class friends of another class. For that, we declare a class or member function as a friend to the other class so that one or all the member functions of the declared class can access the private members of the former class.
For example:
class Breadth;
class Length
{
private:
int data;
......
public:
......
friend int add(Length, Breadth); //friend function declaration
};
class Breadth
{
private:
int data;
......
public:
......
friend int add(Length, Breadth); //friend function declaration
};
int add(Length l, Breadth b) {
int r;
r=l.data+b.data;
return r;
}
Here the function add acts as a bridge between two classes Length and Breadth.
The whole class can be made a friend of another class as follows.
class A;
class B
{
private:
int data;
......
public:
......
friend class A; //Friend class declaration
};
Now all the functions of class A can access private members of class B.
2. The this Pointer
In C++, every object has a special member called the this pointer, which points to the object itself. Every non-static member function of a class has access to a special pointer called this. The this pointer holds the address of the object that calls the member function. It is implicitly passed to every non-static member function by the compiler as a part of the object itself. The this pointer is useful when:
A member function needs to return the calling object itself.
A parameter name is the same as a data member name and needs to be distinguished.
For example:
class Box
{
private:
int length;
public:
void setLength(int length)
{
this->length = length; // this->length is data member,
// length is the parameter
}
Box getLarger(const Box &b)
{
if(length>b.length)
return *this; // returns the calling object itself
else return b;
}
};
Here this->length refers to the data member, while length alone refers to the parameter. The expression *this dereferences the pointer to return the calling object. Static member functions cannot access the this pointer since they are not associated with any particular object.
3. Operator Overloading
Just as built-in types such as int and float support operators like + and -, C++ allows us to extend these operators to work with user-defined types or classes. The data items are represented by objects, and operations on those objects can be extended (defined) with the already existing operators. The method of extending the operation on user-defined types (objects) is called operator overloading. Operators can be overloaded for different operations. Most programmers implicitly use overloaded operators regularly. For example, the addition operator (+) operates quite differently on integers, float and doubles, and other built-in types because the operator (+) has been overloaded in the C++ language itself and with some library objects such as strings. Operators are overloaded by writing a function definition as we normally do, except that the function name now becomes the keyword operator followed by the symbol for the operator being overloaded. Operator overloading provides a flexible option for the creation of new definitions for most of the C++ operators for our class.
The syntax of operator overloading is as follows:
return_type operator operator_symbol (parameters)
{
statements;
}
The operator function can be defined as a member function of a class or a non-member function. The number of parameters required for overloading operators is different for member functions and non-member functions. The number of parameters for a binary operator overloading function as a member function is one, and as a non-member function is two. Similarly, the number of parameters for a unary operator overloading function as a member function is zero, and as a non-member function is one and should be passed by reference so that the modifications affect the original object.
The operator overloading function, when defined as a member function, has the following form.
class test
{
private:
int data;
......
public:
......
test operator + (test t); //one argument for binary and no argument for unary operator
};
test test::operator + (test t)
{
//Addition code.
}
After overloading with a member operator overloading function, it is used as.
test t1,t2,t3;
//...
t3=t1+t2;
The operator overloading function, when defined as a non-member function, has the following form. When the operator overloading function is a non-member, to access the private members of the class, the operator function must be declared as a friend in the class; otherwise, there should be a mechanism to return the values of data members of the objects of the class.
class test
{
private:
int data;
......
public:
......
friend test operator + (test t1, test t2);
};
test operator + (test t1, test t2)
{
//addition code.
}
The usage is similar to the one when the operator function is a member as follows.
test t1,t2,t3;
//...
t3=t1+t2;
For prefix and postfix unary operator overloading, such as for the increment operator, it requires overloading both prefix (++obj) and postfix (obj++) increment operators. The postfix version takes a dummy int parameter to differentiate it from the prefix version as follows.
class test
{
private:
int data;
......
public:
......
test operator ++ (); //prefix
test operator ++ (int); //postfix
};
test test::operator ++ () //prefix increment
{
//increment code.
}
test test::operator ++ (int) //postfix increment
{
//increment code.
}
Now it can be used as
test t1,t2,t3;
//...
t2=++t1;
t3=t2++;
For non-member overloading of unary operators, it is done as follows
class test
{
private:
int data;
......
public:
......
// Pass by reference (&) is mandatory to modify the caller object
friend test operator ++ (test &t1); //prefix
friend test operator ++ (test &t1, int); //postfix
};
test operator ++ (test &t1) // prefix increment
{
//increment code.
}
test operator ++ (test &t1, int) // postfix increment
{
// increment code.
}
The usage of non-member operator overloading function is the same as the member operator function.
Exercises
Write a program to make classes for instantiating the objects that represent the two-dimensional Cartesian coordinate system.
A. Make a particular member function of one class a friend function of another class for addition.
B. Make three non-member friend functions that work as a bridge between two classes for multiplication, division, and subtraction.
C. Demonstrate that all the member functions of one class are the friend functions of another class if the former class is made a friend of the latter.
Implement all three cases within a single program using the minimum number of classes necessary.
Write two classes, Celsius and Fahrenheit, each having a private data member to store the temperature value. Write a non-member friend function convert() that accepts an object of one class and returns the equivalent temperature as an object of the other class. Display both the original and converted temperatures.
Write a class to store x, y, and z coordinates of a point in three-dimensional space. Overload the addition and subtraction operators for the addition and subtraction of two coordinate objects. Implement the operator functions as non-member functions.
Write a program to compare two objects of a class that contains an integer value as its data member. Overload the equality(==), less than(<), greater than(>), not equal (!=), greater than or equal to (>=), and less than or equal to(<=) operators using member operator functions.
Write a class called Fraction that stores the numerator and denominator of a fraction as private data members. Overload the + and - operators as non-member friend functions to add and subtract two Fraction objects, returning the result in its simplified form. Display the result of adding and subtracting at least two Fraction objects. Remember to use HCF while adding and subtracting fractions.
Write a class Date that overloads prefix and postfix operators to increase the Date object by one day, while causing appropriate increments to the month and year (use the appropriate condition for leap year). The prefix and postfix operators in the Date class should behave exactly like the built-in increment operators. Show the use of this pointer when returning the increased object.