|
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 ) ); } |