Friends

* Example, let's say we would like to compare two Jar_Type objects for equality.

class Jar_Type {

public:

...

Boolean equal(const Jar_Type& other) const;

...

private:

int units;

};

* The function compares a Jar_Type object with another.

Jar_Type jar1, jar2;

if (jar1.equal(jar2)) { ... }

// in the .cpp file...

Boolean Jar_Type::equal(const Jar_Type& other) const

{ return (units == other.units);

}

* The client cannot write:

if (equal(jar1, jar2)) { ...

* That would require equal function to be a global function.

Boolean equal(const Jar_Type& jar1,

const Jar_Type& jar2)

{

return (jar1.quantity() == jar2.quantity());

}

* A class may grant permission to non-member functions to access its private members!

class Jar_Type {

public:

friend Boolean equal(const Jar_Type& jar1,

const Jar_Type& jar2);

...

};

* A friend can access the private member "units"!

Boolean equal(......)

{

return (jar1.units == jar2.units);

}

* There is really no need to make the non member function a friend since we can do without it. But we will see examples where it would really come in handy shortly.

* Just like the real life, friends are dangerous! Use them with extra caution!

* In addition to treat a function a friend, you can treat a whole class a friend too!

class A {

friend class B;

...

};

* Now any B's members can access A's private members! Use it with extra extra caution!

Operator overloading

* Normally, the only operators defined for C++ classes are (?) and (?). (page 144).

* However, the programmer can overload many operators to apply to class instances.

* It would really be nice if we can compare two Jar_Type instances using "=="!

class Jar_Type {

public:

Boolean operator == (const Jar_Type& other) const;

};

Jar_Type jar1, jar2;

...

if (jar1 == jar2) {

...

}

* Another example of operator overloading (very common!)

class Jar_Type {

public:

friend ostream& operator << (ostream& ost,

const Jar_Type& jar);

...

};

ostream& operator << (......) {

ost << "I have " << jar.units << " units!\n";

return ost;

}

A Study in Design

#ifndef FRACTION_H

#define FRACTION_H

#include "bool.h" // if not using Mac/Symantec

#include <iostream.h> // why need this?

class Fraction {

public:

Fraction(int in_num, int in_den = 1);

friend ostream& operator << (ostream& ost,

const Fraction& frac);

void simplify();

Fraction operator* (const Fraction& other) const;

Boolean operator== (const Fraction& other) const;

private:

int numerator;

int denominator;

};

#endif

// fraction.cpp

#include "fraction.h"

Fraction::Fraction(int in_num, int in_den)

{

numerator = in_num;

denominator = in_den;

simplify(); // your text forgets to do this!

}

ostream&

operator << (ostream& ost, const Fraction& frac)

{

ost << frac.numerator << "/" << frac.denominator;

return ost;

}

Fraction

Fraction::operator * (const Fraction& other) const

{

Fraction result(numerator * other.numerator,

denominator * other.denominator);

result.simplify();

return result;

}

Boolean

Fraction::operator == (const Fraction& other) const

{

return ((numerator == other.numerator)

&& (denominator == other.denominator));

}

* Note we make sure that a Fraction instance is always simplified so "==" is written that way!

Summary

* Modules and classes are both units of modularity.

* A module is an organization mechanism (may or may not have classes).

* A class is a C++ construct to create ADTs.

* A class is a type.

* The "private" keyword can be used to hide information from the clients.

* Usually, we hide all data members. (why?)

* Usually, we expose many member functions. (why?)