Introduction to Computer Science - C++

Creating User Defined Classes – part two

Friend Functions and Classes

Friend functions are non-member functions that are granted access to private attributes of a class. They are friended to a class even though they are not members of the class. For example, if I have a class item:

class item{
int id;
public:
item(int ID)
{
id=ID;
}
};
and I write a a function
int printItem(item a)
{
cout<<a.id;
}
The function won't work because id is private to the class item. Only member functions have access to the attribute id. But if I make the function printItem a friend of item then the function will work.
class item{
int id;
public:
item(int ID)
{
    id=ID;
}
friend int printItem(item a);
};

Now I have granted access to the non-member function printItem and the function will work. I do not have to make any changes to the function other than friending it. Usually friending is done in the public: section of a class. Friendships are not inherited to children.

What if I had a class dog and a class cat and I wanted a function to compare them. A normal non-member function would not be able to do this since it wouldn't have access to the attributes of dog and cat which I want to compare. Therefore I will need to either make the function a friend of both classes or a member of one and a friend of the other. Making it a member of both classes will not work at all as we shall see shortly.

Lets start with the first option.

class cat; //forward declaration of cat

class dog{
int id;
public:
dog(int ID){id=ID;}
friend bool compare(cat c, dog d);
};

class cat{
int id;
public:
cat(int ID){id=ID;}
friend bool compare(cat c, dog d);

};

bool compare(cat c, dog d)
{
return (c.id > d.id);
}

Since the function compare needs to access private data of cat and dog , it needs to be a friend of both class. Also note that we needed to use a forward declaration of cat so that when the compiler reads class dog it will already know about the existence of cat. This is neccessary since dog mentions cat in the compare function declaration. Remember that compare is not a member of either class, so when I call the function I do not use the dot operator on an instance. I simply call the function normally. See here:

int main()
{
cat ct(10);
dog dg(11);
compare(ct,dg);
}

The other option is to make the function compare a member of one class and a friend of the other. See this example:

class cat; //forward declaration of cat

class dog{
int id;
public:
dog(int ID){id=ID;}
bool compare(cat c);
};

class cat{
int id;
public:
cat(int ID){id=ID;}
friend bool dog::compare(cat c);

};

bool dog::compare(cat c)
{
return (c.id > this->id);
}

Now my main would be written differently. This time I do need to use the dot operator on an instance of class dog.
int main()
{
cat ct(10);
dog dg(11);
dg.compare(ct);
}

The non-existant third option is to make compare a member of both classes. But doing this would cause the functions to have different signatures since one would have a cat as a parameter and the other would have a dog as its parameter. This is in effect like making two overloaded functions. The one that is a member of dog will not have access to its cat parameter's private attributes and the one that is a member of cat will not have access to dog's. This option won't work.

Static

I can declare a member of a class to be static. This means that even before any instance of the class is created, the static members exist. A static member can be either an attribute (value) or a function. Furthermore, a static member of the class exists only once no matter how many instances of the class are created. All instances will have access to the static member. This makes a static member a good way for instances to communicate with one another. It also provides a simple machanism for keeping track of how many instances are created since effectively it is a variable shared among all class instances so each can update it.

You can access a static member in one of three ways. Member functions access static attributes just as they would access other attributes, simply by writing the variable name. Secondly, you can access static attributes through an instance of the class and using the dot operator on it. Thirdly, since a static attribute of a class exists in the class and not in any one instance, therefore you can access it by use the class name followed by the scope resolution operator and then the variable name. Let's see an example:

Note that I must initialize the static variable before I create any instances. Note the technique for doing this below.

class cat
{
public:
  static int count;
  int ID;
  cat(){ID=0;}
  void upCount() {count++;}// First method of accessing static attribute, via function
};
// initialize the  static member
int cat::count=0;
// must specify the type so the compiler knows it is an initialization
// cat::count=1; would fail to compile

main()
{
cat myCat;
myCat.count++;// Second method of accessing static attribute, via instance
cat::count++;// Third method of accessing static attribute, via class name
}

I can also have a static function. It can also be access in the same three ways. Here is an example:

class cat
{
public:
  static int count;
  int ID;
  cat(){ID=0;}
  static void upCount() {count++;}
  void upCountTwice(){ // Accessing static attribute though another function
       upcount();
       upcount()
      }
};
// initialize the  static member
int cat::count=0;

main()
{
cat myCat;
myCat.upCount();// Accessing static function through an instance
cat::upCount;;// Accessing static function through 
              // class name and scope resolution operator
}

Here is a complete example. I will use a static member variable to keep track of how many instances I have created. Each call of a constructor function will increment the value of count, and each destruction will decrement it.

#include <iostream>
using namespace std;

class cat
{
  static int count;
  int ID;
  char * name;
  char * breed;
public:
  ~cat(){delete[]name; delete[]breed; count--;};
  cat(int ID, char * name, char * breed)
  {
    this->ID=ID;
    this->name = new char [strlen(name)+1];
    this->breed = new char[strlen(breed)+1];
    strcpy(this->name,name);
    strcpy(this->breed,breed);
    count++;
  }
  void print()
  {
    cout<<"name: "<<name;
    cout<<" breed: "<<breed;
    cout<<" ID: "<<ID<<endl;
  }
  static int getCount(){return count;}

};

//initialize the private static member
int cat::count=0;


int main()
{
  //I can run static function even before I create an instance.
  cout<<endl<<(cat::getCount())<<endl;

  cat a(123,"fefe","persian");
  //count increments
  cout<<endl<<(cat::getCount())<<endl;

  cat *ptr= new cat(456,"herman","domestic");
  //count increments again
  cout<<endl<<(cat::getCount())<<endl;
  // I can only delete a cat created with new, 
  // i.e. only the second instance created in this example
  delete ptr;
  //the destructor decrements count
  cout<<endl<<(cat::getCount())<<endl;

  return 1;

}

As you can see above, I have made the function getCount() static. When doing this remember that functions cannot be both virtual and static. They must be either virtual or static or neither.

You cannot have a function which is both static and virtual. For example you might want a function called printType to be static since logically this function relates to the class and not to the specific object, all objects get the same output from the function. You might want it to be virtual since it may be a function in a class animal which then inherits to classes cat, dog and fish. This seemingly useful goal cannot be achieved since when you call a function which is virtual you are asking the compiler to relate to this particular object. You have a pointer to animal pointing to cat object. When your function is virtual, you force the compiler to look at the object (not the class which would be animal since your pointer is an animal pointer) to determine which type it is so that it can run the appropriate function. But when a function is static you are saying that the compiler should only look at the class and never the object, since static functions are part of the class not the instance. These two behaviors are mutually exclusive.

Another way to put it, static function can also be called with the class name and the scope resolution operator, i.e . without an instance pointer. This must be allowed for all static functions, but virtual functions require an instance pointer, so the two attributes, static and virtual, have conflicting requirements and therefore cannot be combined.

Example of a protected parent class that allows child instances to be created but only one parent class can be instantiated. The parent is a singleton.

Diagramming Classes.

        Here is the way you should diagram your classes. This will help to organize your program and it will help your teacher to understand how your program works.

Class Name
attribute        
attribute
attribute
attribute
function
function
function
function
The attributes are written above the center line and are assumed to be private unless otherwise specified. The functions are written below the line and are assumed to be public unless otherwise specified.

Containment and Inheritance - "has a" vs. "is a" relationships

        Sometimes one class may contain another class. It is possible in such a case to include the other class in the list of attributes in the new class. For example if I had a class card and a class deck I might observe that a deck contains an array of 52 cards. This is called a "has a" relationship because a deck "has a" card in it. When I notice relationships between parts of my program that logically are "has a" relationships I should use containment.
Assume I already had a class Card defined, here is how I would define class Deck to contain the class Card:

class Deck
{
 Card * array;
 more attributes

//-------------
Deck()//constuctor
{
array = new Card[52];
}
 more functions

}
In this case I made Deck contain 52 cards. Note: the call to new is done in the constuctor. In this case class Deck contains an array of cards, but containment may also be a class containing a single instance of another class, not neccessarily an array.

Alternatively, it may be desirable to give one class the attributes of another by what is called inheriting. Let's say I have two classes Dog and sled_Dog. I may notice that the class sled_Dog has all the same attributes and functions as the class Dog but it also has some additional attributes or functions. For example, maybe sled_Dog has the additional attribute range, as in the number of miles he can pull a sled in one day. Like the above example of a deck of cards I want to re-use one class when making another class. But in this case I cannot say that sled dog contains or "has a" dog in it. A sled dog "is a" dog; it is a kind of dog. This type of relationship is called an "is a" relationship. We could write a new class from scratch called sled_Dog and cut and paste all the code from Dog. But this has a number of deficits: (1) if we decide to change something about Dog, we will have to manually make the same changes in sled_Dog and any other Dog type we may have created, (2)we are not showing the "is a" relationship in any way, and (3) we cannot treat sled_Dog as a Dog since the compiler has no way to know that they are in fact the same.

Instead we use a process called inheritance. One class can inherit all the attributes and functions of another class. The class that inherits is called the child class and the class that inherits to it is called the parent. This gives us code-reuse without having to cut and paste. Any changes made to the code in the "parent" class will show up in the inheriting or "child" class automatically. The child is then free to add additional attributes or functions. Using inheritance is one way to achieve the Object-Oriented Programming goal of polymorphism. That means that we can treat sled_Dogs as though they are Dogs and get desireable results. This is becasue sled_Dog "is a" Dog and we have represented this relationship in code. Anything we can do to Dog we can now do to sled_Dog since sled_Dog is a Dog. Note that Dog is not a sled_Dog. I cannot do everything that I can do to sled_Dog to Dog. The relationship is not convertable. sled_Dog is an expanded Dog, a Dog with more features.

Let's see an example. Assuming the class Dog is already defined, here is how I would define sled_Dog:

class sled_Dog  : public   Dog
{
int range;
 more attributes
 more functions
}
This is actually more concise than cutting and pasting. Later we will see that it is also more powerful. But remember that inheritance should only be used in "is a" relationships.

Calling a Parent's constructor from the child

Since an inherited class (a child or subclass) "is a" parent class or superclass, it will automatically call the default constructor function on the parent class. This will create a parent class for each subclass. This is what actually enables the child to call the superclass functions and enables refering to the subclass with a superclass pointer or reference. Since whenever you write a parameterized constructor function [ myclass(int a, intb) ] you lose the dafault constuctor and when the constructor function of an inherited class is run, it will try to run the parent class's default constructor, you need to make sure that the parent's default constructor is explicity defined! A default constructor is defined as a constuctor with an empty set of parameters.

When you construct a child class you need to assign values to all the members variables including those declared in the parent class. You can do this inside the child's constructor as you would for the child's own member variables, the but alternatively you may want to explicity run the constructor of the parent and simply pass the child's parameters along to him. This is done by using an initialization list. We do this like this:


MyChildClass(int parent_val, int child_val) : MyParentClass(parent_val)
{
this->child_val=child_val;
}

Since we have called the parent constructor explicitly the default constructor will not be called. Nevertheless, one should define a default constuctor in any class one may wish to inherit from in case the inheriting class does not explicitly call the parameterized constructor.

Example

Now I will give an example using two classes, point and circle. This example could be considered either a "has a" or an "is a" relationship since every circle has a point in it, but it also is a point with extra properties. I will show an "is a" inheritance implementation. Here is how to diagram an inheritance relationship.

Class Point
int x_coordinate
int y_coordinate
Point(int x, int y)
setPoint(int x, int y)



Class Circle
float radius
circle(int x, int y, float radius)
double computeArea()

The arrow is meant to mean that circle inherits from point. The arrow points to where the child inherits from. Practically what inheritance means is that class circle in addition to having the attribute radius also has an x_coordinate and a y_coordinate. Circle "inherits" these two attributes from its "parent" class point. ( There is some logical sense to this relationship because a point is really just a circle with a very small radius, in fact, with no radius at all. A circle is a point plus. It has everything a point has plus some extra size, its radius.) You should note that the constructor for circle has all three attributes in it. This is because circle possesses all three attributes.

To use inheritance, we would define Point and then define Circle like this:

class Circle  : public   Point
{
float radius;
circle(int x, int y, float radius):Point(x,y), radius(radius){ }
double computeArea() { return ((double)radius*radius*3.1415); }
}

Private, Public and Protected

Private attributes are only accessable to the class itself. Public attributes are accessable to any and all classes and to the instance itself. Protected is half-way in between public and private. Protected attributes are accessable to classes which inherit from the class but are private to all other classes or functions. Use the key word protected as you would use private or public in the class definition.

Furthermore, inheritance itself can be either public, private or protected. Notice in the example above I wrote the word "public" before I wrote Point. That means that my inheritance of Point is a public inheritance. That means that instances of the derived class (child class) will have access access to any public members of the parent class. Obviously I cannot grant myself access to private members.

Public inheritance is the most normal way to inherit. In fact you can leave out the word public in your inheritance declaration and it is assumed you want public inheritance. (I.e., it is the default form of inheritance.)

The alternate way to inherit is private inheritance. What this does is to deny the child class instance access to all parent members, including public ones.

Protected inheritance also denies the child class instance access to public parent attribute but it allows the next generation's functions to have access to the public and protected parent attributes.

Private, public and protected inheritance does not affect the access of functions in the child to parent attributes or functions.

In any case the child is allowed to override virtual functions in the parent, even if they are private. Privateand protected inheritance both allow the child to override a virtual function. (See virtual functions later)

Example of public, private and protected inheritance
Another example of inheritance

Nested Classes

A nested or inner class is a class which is defined inside another class. For example, inside a class you might write a new class.
For example:
class myClass{
         class myNestedClass {
	                      some code 
	                     }
         myNestedClass a;
}

Here is an example where I create a class Fish with an inner class scales. I gave scales some static data so that I could show you how you can use an inner class even without creating an instance. But I also created an instance scales. Like all classes, inner classes can be instantiated right after the class definition before the semi-colon.

class Fish
{
public:
  int ID;
  static const int stam=9; //const static variables can be initialized inline 
  class scales  //nested class
  {
  public:
    int NumScales;
    static char color;
    scales(){NumScales=Fish::stam;      }

  } s; //create an instance
  //scales s; //alternate way to create instance s
  Fish():ID(1){}
}a ;//create a Fish instance

char Fish::scales::color='g';

int main()
{

  Fish myF;
  cout<<(Fish::scales::color);
  cout<<endl<< a.s.color;
  cout<<endl<< myF.ID;
  cout<<endl<< myF.s.NumScales<<endl;

  return 1;
}

Inner classes could be useful when making a first in first out ( fifo ) list. In such a case, we might make a class "fifo" to contain all our list items. The class "fifo" will use objects of type fifoItem. The outside world will insert data (ints for example) into the fifo. The fifo will construct fifoItems using the data. Only the class "fifo" needs to know about the fifoItem class. In such a case, the fifoItem class should be made as a nested class.

Some facts about inner classes:

© Nachum Danzig June 2010