Activity 8-1 - Friend Function



So far, you have learned to define a class and to use member functions of the class to access the private variable members of that class.  Previously, we mentioned that a private variable member of a class could be accessed by a member function, however, that is not the only way to access a private variable member.   A function can be made a friend of a class, and thus, can be given the authority to access the private variable members of that class.  In such a case, the friend function is not a class member and can be used throughout the program as an independent function.  A friend function not only can access the private variable members, but it can also change them.  One may find it tempting to define all functions used in a program friend of all classes in that program with an argument that in such a case there is no need for accessor or mutator functions.  Although in theory this may be true, it is not practical.  I am sure you can think of several good reasons for not defining all functions as friend of all classes.

In the following program, we will use a class AltMoney to add two dollar amounts.  The class is defined with a member function add that adds the dollars and cents amounts for the two inputs.  Please note that the AltMoney class presented in this lab is a much simpler version of the one in Display 8.3 of the textbook.

// P81.cpp - This program adds two different people's money
#include<iostream>
#include<cstdlib>
using namespace std;

class AltMoney
{
    public:
        AltMoney();
        AltMoney(int d, int c);

        void add(AltMoney m1, AltMoney m2);
        void display_money( );
    private:
        int dollars;
        int cents;
};

void read_money(int& d, int& c);

int main( )
{
     int d, c;
     AltMoney m1, m2, sum;

     sum = AltMoney(0,0);

     read_money(d, c);
     m1 = AltMoney(d,c);
     cout << "The first money is:";
     m1.display_money();

     read_money(d, c);
     m2 = AltMoney(d,c);
     cout << "The second money is:";
     m2.display_money();

     sum.add(m1,m2);
     cout << "The sum is:";
     sum.display_money();

     return 0;
}

AltMoney::AltMoney()
{
}

AltMoney::AltMoney(int d, int c)
{
       dollars = d;
       cents = c;
}

void AltMoney::display_money()
{
     cout << "$" << dollars << "." << cents << endl;
}

void AltMoney::add(AltMoney m1, AltMoney m2)
{
     int extra = 0;
     cents = m1.cents + m2.cents;
     if(cents >=100){
         cents = cents - 100;
         extra = 1;
     }

     dollars = m1.dollars + m2.dollars + extra;
}

void read_money(int& d, int& c)
{
     cout << "Enter dollar \n";
     cin >> d;
     cout << "Enter cents \n";
     cin >> c;
     if( d < 0 || c < 0)
     {
            cout << "Invalid dollars and cents, negative values\n";
            exit(1);
      }
}

In this program, all functions are members of class AltMoney, except read_money.  Suppose, we define the add function as:

void add(AltMoney m1, AltMoney m2)
{
     int extra = 0;
     cents = m1.cents + m2.cents;
     if(cents >=100){
         cents = cents - 100;
         extra = 1;
     }

     dollars = m1.dollars + m2.dollars + extra;
}

As you may have noticed, based on this definition, function add is not a member function any more.  Now, add cannot access the dollars and cents of m1 and m2.  In fact, if you try the program like this, without making any change, you will get several syntax errors.  In order to give add (in its new definition) the authority to access the private variable members, we will make it a friend of class AltMoney.

Here is the new version of P81.cpp program with add as a friend function.

// P81a.cpp - This program adds money of two different people
#include<iostream>
#include<cstdlib>
using namespace std;

class AltMoney
{
    public:
        AltMoney();
        AltMoney(int d, int c);

        friend void add(AltMoney m1, AltMoney m2, AltMoney& sum);
        void display_money( );
    private:
        int dollars;
        int cents;
};

void read_money(int& d, int& c);

int main( )
{
     int d, c;
     AltMoney m1, m2, sum;

     sum = AltMoney(0,0);

     read_money(d, c);
     m1 = AltMoney(d,c);
     cout << "The first money is:";
     m1.display_money();

     read_money(d, c);
     m2 = AltMoney(d,c);
     cout << "The second money is:";
     m2.display_money();

     add(m1,m2, sum);
     cout << "The sum is:";
     sum.display_money();

     return 0;
}

AltMoney::AltMoney()
{
}

AltMoney::AltMoney(int d, int c)
{
       dollars = d;
       cents = c;
}

void AltMoney::display_money()
{
     cout << "$" << dollars << ".";
     if(cents <= 9)
         cout << "0";  //to display a 0 in the left for numbers less than 10
     cout << cents << endl;
}

void add(AltMoney m1, AltMoney m2, AltMoney& sum)
{
     int extra = 0;
     sum.cents = m1.cents + m2.cents;
     if(sum.cents >=100){
         sum.cents = sum.cents - 100;
         extra = 1;
      }
      sum.dollars = m1.dollars + m2.dollars + extra;
}

void read_money(int& d, int& c)
{
     cout << "Enter dollar \n";
     cin >> d;
     cout << "Enter cents \n";
     cin >> c;
     if( d < 0 || c < 0)
     {
            cout << "Invalid dollars and cents, negative values\n";
            exit(1);
      }
}

In this program the function add is no longer a member function, but it is a friend to the class AltMoney and has access to private variable members.  In general, we may want to include the function that does the reading of variables as a function member or make it a friend so that it reads the dollars and cents and directly assigns them to the dollars and cents of an object.

Exercise 8.1
Modify the above program to include the following changes.  Call your new program ex1.cpp.
            1) make function add of type AltMoney.  Thus, this function now computes the sum of dollars and cents and returns it as AltMoney.  Note that in the above version of the program, you have passed the object sum as call_by_reference.
            2) add a new friend function, subtract, that computes the subtraction of one money from the other.
            3) Make read_money a member function.  Note that if you make read_money a member function, then you can use it to directly initialize the dollars and cents of an AltMoney type object directly.