Friend functions. 

 

Let's define a class to represent 2 dimensional points.  Each point has an x coordinate and a y coordinate.

 

Header file Point.h

class Point

{

private:

    double x;

    double y;

public:

    Point();

    Point( /* in */ double, /* in */ double );

    ...

};

 

Implementation file: Point.cpp

#include "point.h"

 

Point::Point()

{

    x = 0.0;

    y = 0.0;

}

 

Point::Point( /* in */ double initX, /* in */ double initY )

{

    x = initX;

    y = intiY;

}

 

Application file: Main.cpp

#include "point.h"

 

void main()

{

    Point p1;     // Creates a point object with coordinates 0,0

    Point p2(3,4); // Creates a point object with coordinates 3,4

}

 

We would like to be able to compare two points for equality.  Let's define a function that takes two points as arguments and returns true if they are equal, and returns false if they are not equal.

 

bool Equal( /* in */ Point p1, /* in */ Point p2 )

{

    return ( ( p1.x == p2.x ) && ( p1.y == p2.y ) );

}

 


Two points are equal if and only if their x coordinates are equal and their y coordinates are equal.

 

Note that the function body accesses the private data members of the Point class.  Normally, such a function won't compile.  But it will compile if we declare the function as a friend function of the Point class.

 

Header file Point.h

class Point

{

private:

    double x;

    double y;

public:

    Point();

    Point( /* in */ double, /* in */ double );

    friend bool Equal( /* in */ Point, /* in */ Point );

    ...

};

 

Implementation file: Point.cpp

#include "point.h"

 

bool Equal( /* in */ Point p1, /* in */ Point p2 )

{

    return ( ( p1.x == p2.x ) && ( p1.y == p2.y ) );

}

 

Application file: Main.cpp

#include "point.h"

#include <assert.h>"

 

void main()

{

    assert(   Equal( Point( 3, 4), Point( 3, 4) ) );

    assert( ! Equal( Point( 3, 4), Point( 4, 3) ) );

}

 

In the above implementation of Equals( ), both arguments are passed by value.

 

Calling Equal( Point( 3, 4), Point( 4, 3) ) ) is equivalent to the following pseudocode:

 

Point p1 = Point( 3, 4);

Point p2 = Point( 4, 3);

Call Equal( p1, p2 )

 

The initialization of p1 will call the default copy constructor.  The default copy constructor will copy the x data member from the argument Point(3,4) to the x data member of p1 and will copy the y data member from the argument Point(4,3) to the y data member of p1.

 


To avoid all this copying, it is preferable to pass the Point arguments by reference.

 

As a general rule it is better to pass objects by reference rather than by value. 

 

Let's change Equals() to use pass by reference.

 

    friend bool Equal( /* in */ const Point&, /* in */ const Point& );

 

Header file Point.h

class Point

{

private:

    double x;

    double y;

public:

    Point();

    Point( /* in */ double, /* in */ double );

    friend bool Equal( /* in */ const Point&, /* in */ const Point& );

    ...

};

 

Implementation file: Point.cpp

#include "point.h"

 

bool Equal( /* in */ const Point& p1, /* in */ const Point& p2)

{

    return ( ( p1.x == p2.x ) && ( p1.y == p2.y ) );

}




 

this

 

We can also code a Point member function to determine if two points are equal.

 

Header file Point.h

class Point

{

private:

    double x;

    double y;

public:

    Point();

    Point( /* in */ double, /* in */ double );

    bool Equal( /* in */ const Point& );

    ...

};

 

Implementation file: Point.cpp

#include "point.h"

 

bool Point::Equal( /* in */ const Point& p2)

{

    return ( ( x == p2.x ) && ( y == p2.y ) );

}

 

Application file: Main.cpp

#include "point.h"

#include <assert.h>"

 

void main()

{

    assert( Point( 3, 4).Equal( Point( 3, 4) ) );

    assert( ! Point( 3, 4).Equal( Point( 4, 3) ) );

}

 

The Equal() member function (like ALL member functions) has a hidden extra parameter. 

The implementation code is equivalent to the following:

 

bool Point::Equal(

//  /* in */ Point* this,          // hidden parameter

    /* in */ const Point& p2)

{

    return ( ( this->x == p2.x ) && ( this->y == p2.y ) );

}

 

The this pointer points to the object that precedes the period in the call.

 

Point( 3, 4).Equal( Point( 3, 4) )

 


 


Programmer defined operators. 

 

In C++ we can define a == operator for our Point class.

 

Header file Point.h

class Point

{

private:

    double x;

    double y;

public:

    Point();

    Point( /* in */ double, /* in */ double );

    friend bool operator==(

        /* in */ const Point&, /* in */ const Point& );

    ...

};

 

Implementation file: Point.cpp

#include "point.h"

 

bool operator==( /* in */ const Point& p1, /* in */ const Point& p2 )

{

    return ( ( p1.x == p2.x ) && ( p1.y == p2.y ) );

}

 

Application file: Main.cpp

#include "point.h"

#include <assert.h>"

 

void main()

{

    assert( ( Point( 3, 4) == Point( 3, 4) ) );

    assert( ! ( Point( 3, 4) == Point( 4, 3) ) );

}

 

We could also implement the == operator by coding a member function.

 

Header file Point.h

class Point

{

private:

    double x;

    double y;

public:

    Point();

    Point( /* in */ double, /* in */ double );

    bool operator==( /* in */ const Point& );

    ...

};

 


Implementation file: Point.cpp

#include "point.h"

 

bool Point::operator==( /* in */ const Point& p2)

{

    return ( ( x == p2.x ) && ( y == p2.y ) );

}

 

The application program is exactly the same whether we implement the == operator with a friend function or with a method.

 

Application file: Main.cpp

#include "point.h"

#include <assert.h>"

 

void main()

{

    assert( ( Point( 3, 4) == Point( 3, 4) ) );

    assert( ! ( Point( 3, 4) == Point( 4, 3) ) );

}

 

===

Let's code a + operator to add two Point objects together.  We will code an operator+ member function.

 

Header file Point.h

class Point

{

private:

    double x;

    double y;

public:

    Point();

    Point( /* in */ double, /* in */ double );

    Point operator+( /* in */ const Point& );

    ...

};

 

Implementation file: Point.cpp

#include "point.h"

 

Point Point::operator+( /* in */ const Point& p2 )

{

    Point sum;

   

    sum.x = x + p2.x;

    sum.y = y + p2.y;

    return sum;

 

//  alternate code:

//  return Point( x + p2.x, y + p2.y );

}


The following code is wrong:

 

Point& Point::operator+( /* in */ const Point& p2 )

{

    Point sum;

   

    sum.x = x + p2.x;

    sum.y = y + p2.y;

    return sum;

}

 

We must not return a reference to the local Point object sum, since it is destroyed when the function returns and we will be left with a reference to a variable that no longer exists.

 

Application file: Main.cpp

#include "point.h"

#include <assert.h>"

 

void main()

{

    assert( ( Point( 1, 2) + Point( 3, 4) ) == Point( 4, 6) )

 

===

Let's code an assignment operator for Point objects.  We will code an operator= member function.

 

Header file Point.h

class Point

{

private:

    double x;

    double y;

public:

    void operator = ( /* in */ const Point& );

    ...

};

 

Implementation file: Point.cpp

#include "point.h"

 

void Point::operator = ( /* in */ const Point& p )

{

    x = p.x;

    y = p.y;

}

 


 

Application file: Main.cpp

#include "point.h"

 

void main()

{

    Point p;

    p = Point( 3, 4);

    assert( p == Point(3,4) );

}

 

If the application programmer codes

 

    Point p1;

    Point p2;

    p1 = p2 = Point( 3, 4);

 

he will receive a syntax error.

 

E.g.       binary '=' : no operator defined which takes a right hand operand of type 'void' (or there is no acceptable conversion)

 

The assignment operator, associates to the right, so

p1 = p2 = Point( 3, 4);

means

p1 = ( p2 = Point( 3, 4) ); 

 

p2 = Point(3,4) is equivalent to

p2.operator=( Point( 3, 4) )

 

p1 = ( p2 = Point( 3, 4) )  is equivalent to

p1.operator=( p2.operator=( Point( 3, 4) ) )

 

The assignment operator has been declared to return void, so ( p2 = Point(3,4) ) evaluates to  void, and thus cannot be assigned to p1.

 

To fix this, let's re-declare the assignment operator to return a Point& instead of void.

 

 

Header file Point.h

class Point

{

private:

    double x;

    double y;

public:

    Point& operator = ( /* in */ const Point& );

    ...

};

 


 

Implementation file: Point.cpp

#include "point.h"

 

Point& Point::operator = ( /* in */ const Point& p )

{

    x = p.x;

    y = p.y;

    return *this;

}

 

Recall that this points to the object that precedes the period in front of the operator= method.

We are returning a reference to the object pointed to by this.

 

Now  ( p2 = Point(3,4) ) copies 3 to p2.x,  copies 4 to p2.y, and then returns a reference to p2.

 

p1 = ( p2 = Point( 3, 4) ) then copies p2.x  (i.e 3 ) to p1.x, and copies p2.y  (i.e. 4) to p1.y.

 

Application file: Main.cpp

#include "point.h"

 

void main()

{

    Point p1;

    Point p2;

    p1 = p2 = Point( 3 ,4);

    assert( p2 == Point( 3, 4 ) );

    assert( p1 == Point( 3, 4 ) );

}