More About Classes

Friends and Members

A motivating example

Suppose we wanted to write a function to compare two Fraction objects. An intuitive function call might be the following:

  Fraction f1(1,2);
  Fraction f2(2,4);

  if ( Equals(f1, f2) )		// compare two fraction objects
     cout << "The fractions are equal";
To achieve this call, we would need to build a function with the following prototype:
  bool Equals(Fraction x, Fraction y);
Notice that this would not be a member function of class Fraction. The sample call did not use the dot-operator. Here's a possible definition of the function:
  bool Equals(Fraction x, Fraction y)
  {
    if ((x.GetNumerator() * y.GetDenominator()) == (y.GetNumerator() * x.GetDenominator()) )
       return true;
    else
       return false;
  }
Note that this algorithm results from finding a common denominator (multiply the two denominators together), adjusting the numerators, then comparing the numerators (integers). Also notice that this function calls upon the accessor functions from the Fraction class -- GetNumerator() and GetDenominator() -- because it is not a member function. It it outside the Fraction class.

Analyzing the situation

Because this function is performing an operation on two Fraction objects, it is probably being written by the author of the Fraction class. As such, it would be easier (and more efficient in run time) to write it this way:

  bool Equals(Fraction x, Fraction y)
  {
    if (x.numerator * y.denominator == y.numerator * x.denominator )
       return true;
    else
       return false;
  }
However, because this is an outside function, it does not have access to private data, so this would be illegal, as is.

An alternative -- the keyword friend

Member function instead of friend


Conversion Constructors

Recall how some of the built-in types allow automatic type conversions, like this:

  int x = 5;
  double y = 4.5, z = 1.2;
  y = x;			// legal, via automatic conversion
  z = x + y;			// legal, using automatic conversion

Automatic type conversions can also be set up for classes, via a conversion constructor


Using const in classes

Remember that const can be used in a variety of places. And everywhere it is applied in code, it:

  1. Expresses an intent on the part of the programmer, which the compiler enforces (i.e. something is not allowed to change, within some scope)
  2. Expresses the intent more clearly to a user (in this case, another portion of code -- i.e. maybe another programmer)
  3. Affects how certain items can be used.

Revisiting const reference parameters


const Member Functions


Declaring const objects


const Member Data


Destructors

In addition to the special Constructor function, classes also have a special function called a destructor.

Declaration:
The destructor looks like the default constructor (constructor with no parameters), but with a ~ in front.  Destructors cannot have parameters, so there can only be one destructor for a class.  Example:  The destructor for the Fraction class would be:

  ~Fraction();

Like the constructor, this function is called automatically (not explicitly)

The destructor's typical job is to do any clean-up tasks (usually involving memory allocation) that are needed, before an object is deallocated.  However, like a constructor, a destructor is a function and can do other things, if desired.

Compile and run this example to see when constructors and destructors are invoked.