- Next chapter
- Previous chapter
- Table of contents

# Chapter 4: Classes

> We're always interested in getting feedback. E-mail us if you like this guide, if you think that important material is omitted, if you encounter errors in the code examples or in the documentation, if you find any typos, or generally just if you feel like e-mailing. Mail to Frank Brokken or use an e-mail form. Please state the concerned document version, found in the title.

In this chapter classes are the topic of discussion. Two special member functions, the constructor and the destructor, are introduced.

In steps we will construct a class `Person`, which could be used in a database application to store a name, an address and a phone number of a person.

Let's start off by introducing the declaration of a `class Person` right away. The class declaration is normally contained in the header file of the class, e.g., `person.h`. The class declaration is generally not called a declaration, though. Rather, the common name for class declarations is class interface, to be distinguished from the definitions of the function members, called the class implementation. Thus, the interface of the `class Person` is given next:

        class Person
        {
            public:                 // interface functions
                void setname(char const *n);
                void setaddress(char const *a);
                void setphone(char const *p);

                char const *getname(void);
                char const *getaddress(void);
                char const *getphone(void);

            private:                // data fields
                char *name;         // name of person
                char *address;      // address field
                char *phone;        // telephone number
        };

The data fields in this class are `name`, `address` and `phone`. The fields are `char *`s which point to allocated memory. The data are `private`, which means that they can only be accessed by the functions of the class `Person`.

The data are manipulated by interface functions which take care of all communication with code outside of the class. Either to set the data fields to a given value (e.g., `setname()`) or to inspect the data (e.g., `getname()`).

Note once again how similar the `class` is to the `struct`. The fundamental difference being that by default classes have private members, whereas structs have public members. Since the convention calls for the public members of a class to appear first, the keyword `private` is needed to switch back from public members to the (default) private situation.

## 4.1: Constructors and destructors

A class in C++ may contain two special categories of member functions which are involved in the internal workings of the class. These member function categories are, on the one hand, the constructors and, on the other hand, the destructor.

The basic forms and functions of these two categories are discussed next.

### 4.1.1: The constructor

The constructor member function has by definition the same name as the corresponding class. The constructor has no return value specification, not even `void`. E.g., for the class `Person` the constructor is `Person::Person()`. The C++ run-time system makes sure that the constructor of a class, if defined, is called when an object of the class is created. It is of course possible to define a class which has no constructor at all; in that case the run-time system either calls no function or it calls a dummy constructor (i.e., a constructor which performs no actions) when a corresponding object is created. The actual generated code of course depends on the compiler (A compiler-supplied constructor in a class which contains composed objects (see section 4.5) will `automatically' call the member initializers, and therefore does perform some actions. We postpone the discussion of such constructors to 4.5.1.).

Objects may be defined at a local (function) level, or at a global level (in which its status is comparable to a global variable.

When an object is a local (non-static) variable of a function, the constructor is called every time the function is called at the point where the variable is defined (a subtlety here is that a variable may be defined implicitly as, e.g., a temporary variable in an expression).

When an object is a static variable, the constructor is called when the function in which the static variable is defined is called for the first time.

When an object is a global variable the constructor is called when the program starts. Note that in even this case the constructor is called even before the function `main()` is started. This feature is illustrated in the following listing:

        #include <iostream>

        // a class Test with a constructor function
        class Test
        {
            public:                 // 'public' function:
                Test();             // the constructor
        };

        Test::Test()                // here is the
        {                           // definition
            cout << "constructor of class Test called\n";
        }

        // and here is the test program:
        Test
            g;                      // global object

        void func()
        {
            Test                    // local object
                l;                  // in function func()

            cout << "here's function func()" << endl;
        }

        int main()
        {
            Test                    // local object
                x;                  // in function main()

            cout << "main() function" << endl;
            func();
            return (0);
        }

The listing shows how a class `Test` is defined which consists of only one function: the constructor. The constructor performs only one action; a message is printed. The program contains three objects of the class `Test`: one global object, one local object in `main()` and one local object in `func()`.

Concerning the definition of a constructor we have the following remarks:

- The constructor has the same name as its class.

- The constructor may not be defined with a return value. This is true for the declaration of the constructor in the class definition, as in:

              class Test
              {
                  public:
                      /* no return value here */ Test();
              };

  and also holds true for the definition of the constructor function, as in:

              /* no return value here */ Test::Test()
              {
                  // statements ...
              }

- The constructor function in the example above has no arguments. Therefore it is also called the default constructor. That the function has no arguments is, however, no requirement per se. We shall later see that it is possible to define constructors with arguments. Once a constructor function is defined explicitly, the default constructor doesn't exist anymore, unless the default constructor is definied explicitly itself.

The constructor of the three objects of the class `Test` in the above listing are called in the following order:

- The constructor is first called for the global object `g`.

- Next the function `main()` is started. The object `x` is created as a local variable of this function and hence the constructor is called again. After this we expect to see the text `main()` `function`.

- Finally the function `func()` is activated from `main()`. In this function the local object `l` is created and hence the constructor is called. After this, the message `here's` `function` `func()` appears.

As expected, the program yields therefore the following output (the text in parentheses is added for illustration purposes):

        constructor of class Test called        (global object g)
        constructor of class Test called        (object x in main())
        main() function
        constructor of class Test called        (object l in func())
        here's function func()

### 4.1.2: The destructor

The second special member function is the destructor. This function is the opposite of the constructor in the sense that it is invoked when an object ceases to exist. For objects which are local non-static variables, the destructor is called when the block in which the object is defined is left: the destructors of objects that are defined in nested blocks of functions are therefore usually called before the function itself terminates. The destructors of objects that are defined somewhere in the outer block of a function are called just before the function returns (terminates). For static or global variables the destructor is called before the program terminates.

However, when a program is interrupted using an `exit()` call, the destructors are called only for global objects which exist at that time. Destructors of objects defined locally within functions are not called when a program is forcefully terminated using `exit()`.

When defining a destructor for a given class the following rules apply:

- The destructor function has the same name as the class but prefixed by a tilde.

- The destructor has neither arguments nor a return value.

The destructor for the class `Test` from the previous section could be declared as follows:

        class Test
        {
            public:
                Test();                    // constructor
                ~Test();                   // destructor
                // any other members
        };

The position of the constructor(s) and destructor in the class definition is dictated by convention: First the constructors are declared, then the destructor, and only then any other members follow.

### 4.1.3: A first application

One of the applications of constructors and destructors is the management of memory allocation. This is illustrated using the class `Person`.

As illustrated at the beginning of this chapter, the class `Person` contains three `private` pointers, all `char *`s. These data members are manipulated by the interface functions. The internal workings of the class are as follows: when a name, address or phone number of a `Person` is defined, memory is allocated to store these data. An obvious setup is described below:

- The constructor of the class makes sure that the data members are initially 0-pointers.

- The destructor releases all allocated memory.

- The defining of a name, address or phone number (by means of the `set...()` functions) consists of two steps. First, previously allocated memory is released. Next, the string which is supplied as an argument to the `set...()` function is duplicated in memory.

- Inspecting a data member by means of one of the `get...()` functions simply returns the corresponding pointer: either a 0-pointer, indicating that the data is not defined, or a pointer to allocated memory holding the data.

The `set...()` functions are illustrated below. Strings are duplicated in this example by an imaginary function `xstrdup()`, which would duplicate a string or terminate the program when the memory pool is exhausted ( As a word to the initiated reader it is noted here that many other ways to handle the memory allocation are possible here: As discussed in section 5, `new` could be used, together with `set_new_handler()`, or exceptions could be used to catch any failing memory allocation. However, since we haven't covered that subject yet, and since these annotations start from C, we used the tried and true method of a `protected allocation function' `xstrdup()` here for didactical reasons.).

        // interface functions set...()
        void Person::setname(char const *n)
        {
            free(name);
            name = xstrdup(n);
        }

        void Person::setaddress(char const *a)
        {
            free(address);
            address = xstrdup(a);
        }

        void Person::setphone(char const *p)
        {
            free(phone);
            phone = xstrdup(p);
        }

Note that the statements `free(...)` in the above listing are executed unconditionally. This never leads to incorrect actions: when a name, address or phone number is defined, the corresponding pointers point to previously allocated memory which should be freed. When the data are not (yet) defined, then the corresponding pointer is a 0-pointer; and `free(0)` performs no action (Actually, free(0) should perform no action. However, later on we'll introduce the operators `new` and `delete`. With the `delete` operator `delete 0` is formally ignored.).

Furthermore it should be noted that this code example uses the standard `C` function `free()` which should be familiar to most `C` programmers. The `delete` statement, which has more ``C++` flavor', will be discussed later.

The interface functions `get...()` are defined now. Note the occurence of the keyword `const` following the parameter lists of the functions: the member functions are const member functions, indicating that they will not modify their object when they're called. The matter of const member functions is postponed to section 4.2, where it will be discussed in greater detail.

        // interface functions get...()
        char const *Person::getname() const
        {
            return (name);
        }

        char const *Person::getaddress() const
        {
           return (address);
        }

        char const *Person::getphone() const
        {
           return (phone);
        }

The destructor, constructor and the class definition are given below.

        // class definition
        class Person
        {
            public:
                Person();          // constructor
                ~Person();         // destructor

                // functions to set fields
                void setname(char const *n);
                void setaddress(char const *a);
                void setphone(char const *p);

                // functions to inspect fields
                char const *getname() const;
                char const *getaddress() const;
                char const *getphone() const;

            private:
                char *name;             // name of person
                char *address;          // address field
                char *phone;            // telephone number
        };

        // constructor
        Person::Person()
        {
            name = 0;
            address = 0;
            phone = 0;
        }

        // destructor
        Person::~Person()
        {
            free(name);
            free(address);
            free(phone);
        }

To demonstrate the usage of the class `Person`, a code example follows next. An object is initialized and passed to a function `printperson()`, which prints the contained data. Note also the usage of the reference operator `&` in the argument list of the function `printperson()`. This way only a reference to a `Person` object is passed, rather than a whole object. The fact that `printperson()` does not modify its argument is evident from the fact that the argument is declared `const`. Also note that the example doesn't show where the destructor is called; this action occurs implicitly when the below function `main()` terminates and hence when its local variable `p` ceases to exist.

It should also be noted that the function `printperson()` could be defined as a `public` member function of the class `Person`.

        #include <iostream>

        void printperson(Person const &p)
        {
            cout << "Name    : " << p.getname() << endl
                 << "Address : " << p.getaddress() << endl
                 << "Phone   : " << p.getphone() << endl;
        }

        int main()
        {
            Person
                p;

            p.setname("Linus Torvalds");
            p.setaddress("E-mail: Torvalds@cs.helsinki.fi");
            p.setphone(" - not sure - ");

            printperson(p);
            return (0);
        }

When `printperson()` receives a fully defined `Person` object (i.e., containing a name, address and phone number), the data are correctly printed. However, when a `Person` object is only partially filled, e.g. with only a name, `printperson()` passes 0-pointers to `cout`. This unesthetic feature can be remedied with a little more code:

        void printperson(Person const &p)
        {
            if (p.getname())
                cout << "Name   : " << p.getname() << "\n";
            if (p.getaddress())
                cout << "Address : " << p.getaddress() << "\n";
            if (p.getphone())
                cout << "Phone  : " << p.getphone() << "\n";
        }

Alternatively, the constructor `Person::Person()` might initialize the members to `printable defaults', like `" ** undefined ** "`.

### 4.1.4: Constructors with arguments

In the above declaration of the class `Person` the constructor has no arguments. C++ allows constructors to be defined with argument lists. The arguments are supplied when an object is created.

For the class `Person` a constructor may be handy which expects three strings: the name, address and phone number. Such a constructor is shown below:

        Person::Person(char const *n, char const *a, char const *p)
        {
            name = xstrdup(n);
            address = xstrdup(a);
            phone = xstrdup(p);
        }

The constructor must be included in the class declaration, as illustrated here:

        class Person
        {
            public:
                Person::Person(char const *n,
                    char const *a, char const *p);
                .
                .
                .
        };

Since C++ allows function overloading, such a declaration of a constructor can co-exist with a constructor without arguments. The class `Person` would thus have two constructors.

The usage of a constructor with arguments is illustrated in the following code fragment. The object `a` is initialized at its definition:

        int main()
        {
            Person
                a("Karel", "Rietveldlaan 37", "542 6044"),
                b;

            return (0);
        }

In this example, the `Person` objects `a` and `b` are created when `main()` is started. For the object `a` the constructor with arguments is selected by the compiler. For the object `b` the default constructor (without arguments) is used.

4.1.4.1: The order of construction

The possibility to pass arguments to constructors offers us the chance to monitor at which exact moment in a program's execution an object is created or destroyed. This is shown in the next listing, using a class `Test`:

        class Test
        {
            public:
                // constructors:
                Test();                    // argument-free
                Test(char const *name);    // with a name argument
                // destructor:
                ~Test();

            private:
                // data:
                char *n;                    // name field
        };

        Test::Test()
        {
            n = xstrdup("without name");
            printf("Test object without name created\n");
        }

        Test::Test(char const *name)
        {
            n = xstrdup(name);
            cout << "Test object " << name << " created" << endl;
        }

        Test::~Test()
        {
            cout << "Test object " << n << " destroyed" << endl;
            free(n);
        }

By defining objects of the class `Test` with specific names, the construction and destruction of these objects can be monitored:

        Test
            globaltest("global");

        void func()
        {
            Test
                functest("func");
        }

        int main()
        {
            Test
                maintest("main");

            func();
            return (0);
        }

This test program thus leads to the following (and expected) output:

        Test object global created
        Test object main created
        Test object func created
        Test object func destroyed
        Test object main destroyed
        Test object global destroyed

## 4.2: Const member functions and const objects

The keyword `const` is often seen in the declarations of member functions following the argument list. This keyword is used to indicate that a member function does not alter the data fields of its object, but only inspects them. Using the example of the class `Person`, the `get...()` functions should be declared `const`:

        class Person
        {
            public:
                .
                .
                // functions to inspect fields
                char const *getname(void) const;
                char const *getaddress(void) const;
                char const *getphone(void) const;

            private:
                .
                .
        };

As is illustrated in this fragment, the keyword `const` occurs following the argument list of functions. Note that in this situation the rule of thumb given in section 3.1.3 applies once again: whichever appears before the keyword `const`, may not be altered and doesn't alter (its own) data.

The same specification must be repeated in the definition of member functions themselves:

        char const *Person::getname() const
        {
            return (name);
        }

A member function which is declared and defined as `const` may not alter any data fields of its class. In other words, a statement like

        name = 0;

in the above `const` function `getname()` would result in a compilation error.

The `const` member functions exist because C++ allows `const` objects to be created, or references to `const` objects to be passed on to functions. For such objects only member functions which do not modify it, i.e., the `const` member functions, may be called. The only exception to this rule are the constructors and destructor: these are called `automatically'. The possibility of calling constructors or destructors is comparable to the definition of a variable `int const max = 10`. In situations like these, no assignment but rather an initialization takes place at creation-time. Analogously, the constructor can initialize its object when the variable is created, but subsequent assignments cannot take place.

The following example shows how a `const` object of the class `Person` can be defined. When the object is created the data fields are initialized by the constructor:

        Person const
            me("Karel", "karel@icce.rug.nl", "542 6044");

Following this definition it would be illegal to try to redefine the name, address or phone number for the object `me`: a statement as

        me.setname("Lerak");

would not be accepted by the compiler. Once more, look at the position of the `const` keyword in the variable definition: `const`, following `Person` and preceding `me` associates to the left: the `Person` object in general must remain unaltered. Hence, if multiple objects were defined here, both would be constant `Person` objects, as in:

        Person const        // all constant Person objects
            kk("Karel", "karel@icce.rug.nl", "542 6044"),
            fbb("Frank", "frank@icce.rug.nl", "403 2223");

Member functions which do not modify their object should be defined as `const` member functions. This subsequently allows the use of these functions with `const` objects or with `const` references.

## 4.3: The operators new and delete

The C++ language defines two operators which are specific for the allocation and deallocation of memory. These operators are `new` and `delete`.

The most basic example of the use of these operators is given below. An `int` pointer variable is used to point to memory which is allocated by the operator `new`. This memory is later released by the operator `delete`.

        int
            *ip;

        ip = new int;
        // any other statements
        delete ip;

Note that `new` and `delete` are operators and therefore do not require parentheses, which are required for functions like `malloc()` and `free()`. The operator `delete` returns `void`, the operator `new` returns a pointer to the kind of memory that's asked for by its argument (e.g., a pointer to an `int` in the above example).

### 4.3.1: Allocating and deallocating arrays

When the operator `new` is used to allocate an array, the size of the variable is placed between square brackets following the type:

        int
            *intarr;

        intarr = new int [20];    // allocates 20 ints

The syntactical rule for the operator `new` is that this operator must be followed by a type, optionally followed by a number in square brackets. The type and number specification lead to an expression which is used by the compiler to deduce its size; in C an expression like `sizeof(int[20])` might be used.

An array is deallocated by using the operator `delete`:

        delete [] intarr;

In this statement the array operators `[]` indicate that an array is being deallocated. The rule of thumb here is: whenever `new` is followed by `[]`, `delete` should be followed by it too.

What happens if `delete` rather than `delete []` is used? Consider the following situation: a `class X` is defined having a destructor telling us that it's called. In a `main()` function an array of two `X` objects is allocated by new, to be deleted by `delete []`. Next, the same actions are repeated, albeit that the `delete` operator is called without `[]`:

    #include <iostream>

    class X
    {
        public:
            ~X();
    };

    X::~X()
    {
        cout << "X destructor called" << endl;
    }

    int main()
    {
        X
          *a;

        a = new X[2];

        cout << "Destruction with []'s" << endl;

        delete [] a;

        a = new X[2];

        cout << "Destruction without []'s" << endl;

        delete a;

        return (0);
    }

Here's the generated output:

        Destruction with []'s
        X destructor called
        X destructor called
        Destruction without [] 's
        X destructor called

So, as we can see, the destructor of the individual `X` objects are called if the `delete []` syntax is followed, and not if the `[]` is omitted.

If no destructor is defined, it is not called. Consider the following fragment:

    #include <iostream>

    class X
    {
        public:
            ~X();
    };

    X::~X()
    {
        cout << "X destructor called" << endl;
    }

    int main()
    {
        X
          **a;

        a = new X* [2];

        a[0] = new X [2];
        a[1] = new X [2];

        delete [] a;

        return (0);
    }

This program produces no messages at all. Why is this? The variable `a` is defined as a pointer to a pointer. For this situation, however, there is no defined destructor as we do not have something as a 'class pointer to X objects'. Consequently, the `[]` is ignored.

Now, because of the `[]` being ignored, not all elements of the array `a` points to are considered when `a` is deleted. The two pointer elements of `a` are deleted, though, because `delete a` (note that the `[]` is not written here) frees the memory pointed to by `a`. That's all there is to it.

What if we don't want this, but require the `X` objects pointed to by the elements of `a` to be deleted as well? In this case we have two options:

- Explicitly walk all the elements of the `a` array, deleting them in turn. This will call the destructor for a pointer to `X` objects, which will destroy all elements if the `[]` operator is used, as in:

      #include <iostream>

      class X
      {
          public:
              ~X();
      };

      X::~X()
      {
          cout << "X destructor called" << endl;
      }

      int main()
      {
          X
            **a;

          a = new X* [2];

          a[0] = new X [2];
          a[1] = new X [2];

          for (int index = 0; index < 2; index++)
              delete [] a[index];

          delete a;

          return (0);
      }

- Define a class containing a pointer to `X` objects, and allocate a pointer to this super-class, rather than a pointer to a pointer to `X` objects. The topic of containing classes in classes, composition, is discussed in section 4.5.

### 4.3.2: New and delete and object pointers

The operators `new` and `delete` are also used when an object of a given class is allocated. As we have seen in the previous section, the advantage of the operators `new` and `delete` over functions like `malloc()` and `free()` lies in the fact that `new` and `delete` call the corresponding constructors or destructor. This is illustrated in the next example:

        Person
            *pp;                    // ptr to Person object

        pp = new Person;            // now constructed
        ...
        delete pp;                  // now destroyed

The allocation of a new `Person` object pointed to by `pp` is a two-step process. First, the memory for the object itself is allocated. Second, the constructor is called which initializes the object. In the above example the constructor is the argument-free version; it is however also possible to choose an explicit constructor:

        pp = new Person("Frank", "Oostumerweg 17", "050 403 2223");
        ...
        delete pp;

Note that, analogously to the construction of an object, the destruction is also a two-step process: first, the destructor of the class is called to deallocate the memory used by the object. Then the memory which is used by the object itself is freed.

Dynamically allocated arrays of objects can also be manipulated with `new` and `delete`. In this case the size of the array is given between the `[]` when the array is created:

        Person
            *personarray;

        personarray = new Person [10];

The compiler will generate code to call the default constructor for each object which is created. As we have seen, the array operator `[]` must be used with the `delete` operator to destroy such an array in the proper way:

        delete [] personarray;

The presence of the `[]` ensures that the destructor is called for each object in the array. Note again that `delete personarray` would only release the memory of the array itself.

### 4.3.3: The function set_new_handler()

The C++ run-time system makes sure that when memory allocation fails, an error function is activated. By default this function returns the value 0 to the caller of `new`, so that the pointer which is assigned by `new` is set to zero. The error function can be redefined, but it must comply with a few prerequisites, which are, unfortunately, compiler-dependent. E.g., for the Microsoft `C/C++` compiler version 7, the prerequisites are:

- The function is supplied one argument, a `size_t` value which indicates how many bytes should have been allocated (The type `size_t` is usually identical to `unsigned`.).

- The function must return an `int`, which is the value passed by `new` to the assigned pointer.

The Gnu `C/C++` compiler `gcc`, which is present on many Unix platforms, requires that the error handler:

- has no arguments, and

- returns no value (a `void` return type).

Then again, Microsoft's `Visual C++` interprets the returnvalue of the the function as follows:

- The run-time system retries allocation each time the function returns a nonzero value and fails new if the function returns 0.

In short: there's no standard here, so make sure that you lookup the particular characteristics of the `set_new_handler` function for your compiler. Whatever you do, in any case make sure you use this function: it saves you a lot of checks (and problems with a failing allocation that you just happened to forget to protect with a check...).

The redefined error function might, e.g., print a message and terminate the program. The user-written error function becomes part of the allocation system through the function `set_new_handler()`, defined in the header file `new.h`. With some compilers, the installing function is called `_set_new_handler()` (note the leading underscore).

The implementation of an error function is illustrated below. This implementation applies to the `Gnu` C/C++ requirements ( The actual try-out of the program is not encouraged, as it will slow down the computer enormously due to the resulting occupation of Unix's swap area):

        #include <new.h>
        #include <iostream>

        void out_of_memory()
        {
            cout << "Memory exhausted. Program terminates." << endl;
            exit(1);
        }

        int main()
        {
            int
                *ip;
            long
                total_allocated = 0;

            // install error function
            set_new_handler(out_of_memory);

            // eat up all memory
            puts("Ok, allocating..");
            while (1)
            {
                ip = new int [10000];
                total_allocated += 10000 * sizeof(int);
                printf("Now got a total of %ld bytes\n",
                        total_allocated);
            }

            return (0);
        }

The advantage of an allocation error function lies in the fact that once installed, `new` can be used without wondering whether the allocation succeeded or not: upon failure the error function is automatically invoked and the program exits. It is good practice to install a `new` handler in each C++ program, even when the actual code of the program does not allocate memory. Memory allocation can also fail in not directly visible code, e.g., when streams are used or when strings are duplicated by low-level functions.

Note that it may not be assumed that the standard C functions which allocate memory, such as `strdup()`, `malloc()`, `realloc()` etc. will trigger the `new` handler when memory allocation fails. This means that once a `new` handler is installed, such functions should not automatically be used in an unprotected way in a C++ program. As an example of the use of `new` for duplicating a string, a rewrite of the function `strdup()` using the operator `new` is given in section 5. It is strongly suggested to revert to this approach, rather than to using functions like `xstrdup()`, when the allocation of memory is required.

## 4.4: The keyword inline

Let us take another look at the implementation of the function `Person::getname()`:

        char const *Person::getname() const
        {
            return (name);
        }

This function is used to retrieve the name field of an object of the class `Person`. In a code fragment, like:

        Person
            frank("Frank", "Oostumerweg 17", "403 2223");

        puts(frank.getname());

the following actions take place:

- The function `Person::getname()` is called.

- This function returns the value of the pointer `name` of the object `frank`.

- This value, which is a pointer to a string, is passed to `puts()`.

- The function `puts()` finally is called and prints a string.

Especially the first part of these actions leads to some time loss, since an extra function call is necessary to retrieve the value of the `name` field. Sometimes a faster process may be desirable, in which the `name` field becomes immediately available; thus avoiding the call to `getname()`. This can be realized by using `inline` functions, which can be defined in two ways.

### 4.4.1: Inline functions within class declarations

Using the first method to implement `inline` functions, the code of a function is defined in a class declaration itself. For the class `Person` this would lead to the following implementation of `getname()`:

        class Person
        {
            public:
                ...
                char const *getname(void) const
                {
                    return (name);
                }
                ...
        };

Note that the code of the function `getname()` now literally occurs in the interface of the class `Person`. The keyword `const` occurs after the function declaration, and before the code block.

Thus, `inline` functions appearing in the class interface show their full (and standard) definition within the class interface itself.

The effect of this is the following. When `getname()` is called in a program statement, the compiler generates the code of the function when the function is used in the source-text, rather than a call to the function, appearing only once in the compiled program.

This construction, where the function code itself is inserted rather than a call to the function, is called an inline function. Note that the use of inline function results in duplication of the code of the function for each invokation of the inline function. This is probably ok if the function is a small one, and needs to be executed fast. It's not so desirable if the code of the function is extensive.

### 4.4.2: Inline functions outside of class declarations

The second way to implement inline functions leaves a class interface intact, but mentions the keyword `inline` in the function definition. The interface and implementation in this case are as follows:

        class Person
        {
            public:
                ...
                char const *getname(void) const;
                ...
        };

        inline char const *Person::getname() const
        {
            return (name);
        }

Again, the compiler will insert the code of the function `getname()` instead of generating a call.

However, the `inline` function must still appear in the same file as the class interface, and cannot be compiled to be stored in, e.g., a library. The reason for this is that the compiler rather than the linker must be able to insert the code of the function in a source text offered for compilation. Code stored in a library is inaccessible to the compiler. Consequently, inline functions are always defined together with the class interface.

### 4.4.3: When to use inline functions

When should `inline` functions be used, and when not? There is a number of simple rules of thumb which may be followed:

- In general `inline` functions should not be used. Voilà, that's simple, isn't it?

- Defining `inline` functions can be considered once a fully developed and tested program runs too slowly and shows `bottlenecks' in certain functions. A profiler, which runs a program and determines where most of the time is spent, is necessary for such optimization.

- `inline` functions can be used when member functions consist of one very simple statement (such as the return statement in the function `Person::getname()`).

- By defining a function as `inline`, its implementation is inserted in the code wherever the function is used. As a consequence, when the implementation of the inline function changes, all sources using the inline function must be recompiled. In practice that means that all functions must be recompiled that include (either directly or indirectly) the header file of the class in which the inline function is defined.

- It is only useful to implement an `inline` function when the time which is spent during a function call is long compared to the code in the function. An example where an `inline` function has no effect at all is the following:

              void Person::printname() const
              {
                  cout << name << endl;
              }

  This function, which is, for the sake of the argument, presumed to be a member of the class `Person`, contains only one statement.

  However, the statement takes a relatively long time to execute. In general, functions which perform input and output take lots of time. The effect of the conversion of this function `printname()` to `inline` would therefore lead to a very insignificant gain in execution time.

All `inline` functions have one disadvantage: the actual code is inserted by the compiler and must therefore be known compile-time. Therefore, as mentioned earlier, an `inline` function can never be located in a run-time library. Practically this means that an `inline` function is placed near the interface of a class, usually in the same header file. The result is a header file which not only shows the declaration of a class, but also part of its implementation, thus blurring the distinction between interface and implementation.

Finally, note that using the keyword `inline` is not really an order for the compiler. Rather, it is a suggestion the compiler may either choose to follow or to ignore.

## 4.5: Objects in objects: composition

An often recurring situation is one where objects are used as data fields in class definitions. This is referred to as composition.

For example, the class `Person` could hold information about the name, address and phone number, but additionally a class `Date` could be used to keep the information about the birth date:

        class Person
        {
            public:
                // constructor and destructor
                Person();
                Person(char const *nm, char const *adr,
                        char const *ph);
                ~Person();

                // interface functions
                void setname(char const *n);
                void setaddress(char const *a);
                void setphone(char const *p);
                void setbirthday(int yr, int mnth, int d);

                char const *getname() const;
                char const *getaddress() const;
                char const *getphone() const;
                int getbirthyear() const;
                int getbirthmonth() const;
                int getbirthday() const;

            private:
                // data fields
                char *name, *address, *phone;
                Date birthday;
        };

We shall not further elaborate on the class `Date`: this class could, e.g., consist of three `int` data fields to store a year, month and day. These data fields would be set and inspected using interface functions `setyear()`, `getyear()` etc..

The interface functions of the class `Person` would then use `Date`'s interface functions to manipulate the birth date. As an example the function `getbirthyear()` of the class `Person` is given below:

        int Person::getbirthyear() const
        {
            return (birthday.getyear());
        }

Composition is not extraordinary or C++ specific: in C it is quite common to include `struct`s or `union`s in other compound types. Note that the composed objects can be reached through their member functions: the normal field selector operators are used for this.

However, the initialization of the composed objects deserves some extra attention: the topics of the coming sections.

### 4.5.1: Composition and const objects: const member initializers

Composition of objects has an important consequence for the constructor functions of the `composed' (embedded) object. Unless explicitly instructed otherwise, the compiler generates code to call the default constructors of all composed classes in the constructor of the composing class.

Often it is desirable to initialize a composed object from the constructor of the composing class. This is illustrated below for the composed class `Date` in a `Person`. In this fragment it assumed that a constructor for a `Person` should be defined expecting six arguments: the name, address and phone number plus the year, month and day of the birth date. It is furthermore assumed that the composed class `Date` has a constructor with three `int` arguments for the year, month and day:

        Person::Person(char const *nm, char const *adr,
                        char const *ph,
                        int d, int m, int y)
        :
            birthday(d, m, y)
        {
            name = xstrdup(nm);
            address = xstrdup(adr);
            phone = xstrdup(ph);
        }

Note that following the argument list of the constructor `Person::Person()`, the constructor of the data field `Date` is specifically called, supplied with three arguments. This constructor is explicitly called for the composed object `birthday`. This occurs even before the code block of `Person::Person()` is executed. This means that when a `Person` object is constructed and when six arguments are supplied to the constructor, the `birthday` field of the object is initialized even before `Person`'s own data fields are set to their values.

In this situation, the constructor of the composed data member is also referred to as member initializer.

When several composed data members of a class exist, all member initializers can be called using a `constructor list': this list consists of the constructors of all composed objects, separated by commas.

When member initializers are not used, the compiler automatically supplies a call to the default constructor (i.e., the constructor without arguments). In this case a default constructor must have been defined in the composed class.

Member initializers should be used as much as possible: not using member initializers can result in inefficient code, and can be downright necessary. As an example showing the inefficiency of not using a member initializer, consider the following code fragment where the `birthday` field is not initialized by the `Date` constructor, but instead the `setday()`, `setmonth()` and `setyear()` functions are called:

        Person::Person(char const *nm, char const *adr,
                        char const *ph,
                        int d, int m, int y)
        {
            name = xstrdup(nm);
            address = xstrdup(adr);
            phone = xstrdup(ph);

            birthday.setday(d);
            birthday.setmonth(m);
            birthday.setyear(y);
        }

This code is inefficient because:

- first the default constructor of `birthday` is called (this action is implicit),

- and subsequently the desired date is set explicitly by member functions of the class `Date`.

This method is not only inefficient, but even more: it may not work when the composed object is declared as a `const` object. A data field like `birthday` is a good candidate for being `const`, since a person's birthday usually doesn't change.

This means that when the definition of a `Person` is changed so that the data member `birthday` is declared as a `const` object, the implementation of the constructor `Person::Person()` with six arguments must use member initializers. Calling the `birthday.set...()` would be illegal, since these are no `const` functions.

Concluding, the rule of thumb is the following: when composition of objects is used, the member initializer method is preferred to explicit initialization of the composed object. This not only results in more efficient code, but it also allows the composed object to be declared as a `const` object.

### 4.5.2: Composition and reference objects: reference member initializers

Apart from using member initializers to initialize composed objects (be they `const` objects or not), there is another situation where member initializers must be used. Consider the following situation.

A program uses an object of the class `Configfile`, defined in `main()` to access the information in a configuration file. The configuration file contains parameters of the program which may be set by changing the values in the configuration file, rather than by supplying command line arguments.

Assume that another object that is used in the function `main()` is an object of the class `Process`, doing `all the work'. What possibilities do we have to tell the object of the class `Process` that an object of the class `Configfile` exists?

- The objects could have been declared as global objects. This is a possibility, but not a very good one, since all the advantages of local objects are lost.
- The `Configfile` object may be passed to the `Process` object at construction time. Passing an object in a blunt way (i.e., by value) might not be a very good idea, since the object must be copied into the `Configfile` parameter, and then a data member of the `Process` class can be used to make the `Configfile` object accessible throughout the `Process` class. This might involve yet another object-copying task, as in the following situation:

          Process::Process(Configfile conf)   // a copy from the caller
          {
              conf_member = conf;             // copying to conf_member
              ...
          }

- The copy-instructions can be avoided by using pointers to the `Configfile` objects, as in:

          Process::Process(Configfile *conf)  // a pointer to an external object
          {
              conf_ptr = conf;                // the conf_ptr is a Configfile *
              ...
          }

  This construction as such is ok, but forces us to use the `->` field selector operator, rather than the `.` operator, which is (disputably) awkward: conceptually one tends to think of the `Configfile` object as an object, and not as a pointer to an object. In C this would probably have been the preferred method, but in C++ we can do better.
- Rather than using value or pointer parameters, the `Configfile` parameter could be defined as a reference parameter to the `Process` constructor. Next, we can define a `Config` reference data member in the `class Process`. Using the reference variable effectively uses a pointer, disguised as a variable.

However, the following construction will not result in the correct initialization of the `Configfile &conf_ref` reference data member:

        Process::Process(Configfile &conf)
        {
            conf_ref = conf;        // wrong: no assignment
        }

The statement `conf_ref = conf` fails, because the compiler won't see this as an initialization, but considers this an assignment of one `Configfile` object (i.e., `conf`), to another (`conf_ref`). It does so, because that's the normal interpretation: an assignment to a reference variable is actually an assignment to the variable the reference variable refers to. But to what variable does `conf_ref` refer? To no variable, since we haven't initialized `conf_ref`. After all, the whole purpose of the statement `conf_ref = conf` was to initialize `conf_ref`....

So, how do we proceed when `conf_ref` must be initialized? In this situation we once again use the member-initializer syntax. The following example shows the correct way to initialize `conf_ref`:

        Process::Process(Configfile &conf)
        :
            conf_ref(conf)      // initializing reference member
        {
            ...
        }

Note that this syntax can be used in all cases where reference data members are used. If `int_ref` would be an `int` reference data member, a construction like

        Process::Process(int &ir)
        :
            int_ref(ir)
        {
            ...
        }

would have been called for.

## 4.6: Friend functions and friend classes

As we have seen in the previous sections, `private` data or function members are normally only accessible by the code which is part of the corresponding class. However, situations may arise in which it is desirable to allow the explicit access to `private` members of one class to one or more other classless functions or member functions of classes.

E.g., consider the following code example (all functions are `inline` for purposes of brevity):

        class A                         // class A: just stores an
        {                               // int value via the constructor
            public:                     // and can retrieve it via
                A(int v)                // getval
                    { value = v; }
                int getval()
                    { return (value); }

            private:
                int value;
        };

        void decrement(A &a)            // function decrement: tries
        {                               // to alter A's private data
            a.value--;
        }

        class B                         // class B: tries to touch
        {                               // A's private parts
            public:
                void touch(A &a)
                    { a.value++; }
        };

This code will not compile, since the classless function `decrement()` and the function `touch()` of the class `B` attempt to access a `private` datamember of `A`.

We can explicitly allow `decrement()` to access `A`'s data, and we can explicitly allow the class `B` to access these data. To accomplish this, the offending classless function `decrement()` and the class `B` are declared to be friends of `A`:

        class A
        {
            public:
                friend class B;             // B's my buddy, I trust him

                friend void decrement(A     // decrement() is also a good pal
                    &what);
                ...
        };

Concerning friendship between classes, we remark the following:

- Friendship is not mutual by default. This means that once `B` is declared as a friend of `A`, this does not give `A` the right to access `B`'s private members.

- Friendship, when applied to program design, is an escape mechanism which circumvents the principle of data hiding. Using friend classes should therefore be minimized to those cases where it is absolutely essential.

- If friends are used, realize that the implementation of classes or functions that are friends to other classes become implementation dependent on these classes. In the above example: once the internal organization of the data of the class `A` changes, all its friends must be recompiled (and possibly modified) as well.

- As a rule of thumb: don't use friend functions or classes.

Having thus issued some warnings against the use of friends, we'll leave our discussion of friends for the time being. However, in section 13 we'll continue the discussion, having covered, by that time, the topic of operator overloading.

## 4.7: Header file organization with classes

In section 2.5.11 the requirements for header files when a C++ program also uses C functions were discussed.

When classes are used, there are more requirements for the organization of header files. In this section these requirements are covered.

First, the source files. With the exception of the occasional classless function, source files should contain the code of memberfunctions of classes. With source files there are basically two approaches:

- All required header files for a memberfunction are included in each individual source file.
- All required header files for all memberfunctions are included in the class-headerfile, and each sourcefile of that class includes only the header file of its class.

The first alternative has the advantage of economy for the compiler: it only needs to read the header files that are necessary for a particular source file. It has the disadvantage that the program developer must include multiple header files again and again in sourcefiles: it both takes time to type in the `include`-directives and to think about the header files which are needed in a particular source file.

The second alternative has the advantage of economy for the program developer: the header file of the class accumulates header files, so it tends to become more and more generally useful. It has the disadvantage that the compiler will often have to read header files which aren't actually used by the function defined in the source file.

With computers running faster and faster we think the second alternative is to be preferred over the first alternative. So, we suggest that source files of a particular class `MyClass` are organized according to the following example:

        #include <myclass.h>

        int MyClass::aMemberFunction()
        {
            ...
        }

There is only one `include`-directive. Note that the directive refers to a header file in a directory mentioned in the `INCLUDE`-file environment variable. Local header files (using `#include "myclass.h"`) could be used too, but that tends to complicate the organization of the class header file itself somewhat. If name-collisions with existing header files might occur it pays off to have a subdirectory of one of the directories mentioned in the `INCLUDE` environment variable (comparable to, e.g., the `sys` subdirectory). If `class MyClass` is developed as part of some larger project, create a subdirectory (or subdirectory link) of one of the `INCLUDE` directories, to contain all header files of all classes that are developed as part of the project. The `include`-directives will then be similar to `#include <myproject/myclass.h>`, and name collisions with other header files are avoided.

The organization of the header-file itself requires some attention. Consider the following example, in which two classes `File` and `String` are used. The `File` class has a member `gets(String &destination)`, which reads a line from a file, and stores the line in the `String` object passed to the `gets()` member function as reference, while the class `String` has a member function `getLine(File &file)`, which reads one line from the `File` object which is passed to the `getLine()` member function as a reference. The (partial) header file for the `class String` is then:

        #ifndef _String_h_
        #define _String_h_

        #include <project/file.h>   // to know about a File

        class String
        {
            public:
                void getLine(File &file);
            ...
        };
        #endif

However, a similar setup is required for the class `File`:

        #ifndef _File_h_
        #define _File_h_

        #include <project/string.h>   // to know about a String

        class File
        {
            public:
                void gets(String &string);
            ...
        };
        #endif

Now we have created a problem. The compiler, trying to compile `File::gets()` proceeds as follows:

- The header file `project/string.h` is opened to be read
- `_String_h_` is defined
- The header file `project/file.h` is opened to be read
- `_File_h_` is defined
- The header file `project/string.h` is opened to be read
- `_String_h_` has been defined, so `project/string.h` is skipped
- The definition of the `class File` is parsed.
- In the class definition contains a reference to a `String` object
- As the `class String` hasn't been parsed yet, a `String` is an undefined type, and the compiler quits with an error.

The solution for this problem is to use a forward class reference before the class definition, and to include the corresponding class header file after the class definition. So we get:

        #ifndef _String_h_
        #define _String_h_

        class File;                 // forward reference

        class String
        {
            public:
                void getLine(File &file);
            ...
        };

        #include <project/file.h>   // to know about a File

        #endif

However, a similar setup is required for the class `File`:

        #ifndef _File_h_
        #define _File_h_

        class String;               // forward reference

        class File
        {
            public:
                void gets(String &string);
            ...
        };

        #include <project/string.h>   // to know about a String

        #endif

This works well in all situations where either references or pointers to another class are involved. But it doesn't work with composition. Assume the class `File` has a composed data member of the class `String`. In that case, the class definition of the class `File` must include the header file of the class `String` before the class definition itself, because otherwise the compiler can't tell how big a `File` object will be, as it doesn't know the size of a `String` object once the definition of the `File` class is completed.

In cases where classes contain composed objects (or are derived from other classes, see chapter 14) the header files of the classes of the composed objects must have been read before the class definition itself. In such a case the `class File` might be defined as follows:

        #ifndef _File_h_
        #define _File_h_

        #include <project/string.h>   // to know about a String

        class File
        {
            public:
                void gets(String &string);
            ...
            private:
                String              // composition !
                    line;
        };
        #endif

Note that the class `String` can't have a `File` object as a composed member: such a situation would result again in an undefined class while compiling the sources of these classes.

All other required header files are either related to classes that are used only within the source files themselves (without being part of the current class definition), or they are related to classless functions (like `memcpy()`). All headers that are not required by the compiler to parse the current class definition can be mentioned below the class definition.

To summarize, a `class` header file should be organized as follows:

- Everything is contained within the block defined by the standard `ifndef` and `endif` directives.
- Header files of classes of objects that are either composed or inherited (see chapter 14) are mentioned first.
- The classes of objects appearing only as references or as pointers in the class definition are specified as forward references.
- Next comes the class definition itself.
- Following the class definition the header files of all classes given as forward references are included.
- Finally, all other header files that are required in the source files of the class are included.

An example of such an header file is:

        #ifndef _File_h_
        #define _File_h_

        #include <fstream>    // for composed 'instream'

        class String;           // forward reference

        class File              // class definition
        {
            public:
                void gets(String &string);
            ...
            private:
                ifstream
                    instream;
        };
                                // for the class String
        #include <project/string.h>

                                // for remaining software
        #include <memory.h>
        #include <sys/stat.h>

        #endif

## 4.8: Nesting Classes

Classes can be defined inside other classes. Classes that are defined inside other classes are called nested classes.

A class can be nested in every part of the surrounding class: in the `public, protected` or `private` section. Such a nested class can be considered a member of the surrounding class. The normal access and visibility rules in classes apply to nested classes. If a class is nested in the `public` section of a class, it is visible outside the surrounding class. If it is nested in the `protected` section it is visible in subclasses, derived from the surrounding class (see chapter 14), if it is nested in the `private` section, it is only visible for the members of the surrounding class.

The surrounding class has no privileges with respect to the nested class. So, the nested class still has full control over the accessibility of its members by the surrounding class.

For example, consider the following class definition:

    class Surround
    {
        public:
            class FirstWithin
            {
                public:
                    FirstWithin();
                    int getVar() const
                    {
                        return (variable);
                    }
                private:
                    int
                        variable;
            };
        private:
            class SecondWithin
            {
                public:
                    SecondWithin();
                    int getVar() const
                    {
                        return (variable);
                    }
                private:
                    int
                        variable;
            };
            // other private members of Surround
    };

In this definition access to the members is defined as follows:

- The class `FirstWithin` is visible both outside and inside `Surround`. The class `FirstWithin` has therefore global scope.
- The constructor `FirstWithin()` and the memberfunction `getVar()` of the class `FirstWithin` are also globally visible.
- The `int variable` datamember is only visible for the members of the class `FirstWithin`. Neither the members of `Surround` nor the members of `SecondWithin` can access the `variable` of the class `FirstWithin` directly.
- The class `SecondWithin` is visible only inside `Surround`. The public members of the class `SecondWithin` can also be used by the members of the class `FirstWithin`, as nested classes can be considered members of their surrounding class.
- The constructor `SecondWithin()` and the memberfunction `getVar()` of the class `SecondWithin` can also only be reached by the members of `Surround` (and by the members of its nested classes).
- The `int variable` datamember of the class `SecondWithin` is only visible for the members of the class `SecondWithin`. Neither the members of `Surround` nor the members of `FirstWithin` can access the `variable` of the class `SecondWithin` directly.

If the surrounding class should have access rights to the private members of its nested classes or if nested classes should have access rights to the private members of the surrounding class, the classes can be defined as `friend` classes (see section 4.8.3).

The nested classes can be considered members of the surrounding class, but the members of nested classes are not members of the surrounding class. So, a member of the class `Surround` may not access `FirstWithin::getVar()` directly. This is understandable considering the fact that a `Surround` object is not also a `FirstWithin` or `SecondWithin` object. The nested classes are only available as typenames. They do not imply containment as objects by the surrounding class. If a member of the surrounding class should use a (non-static) member of a nested class then a pointer to a nested class object or a nested class datamember must be defined in the surrounding class, which can thereupon be used by the members of the surrounding class to access members of the nested class.

For example, in the following class definition there is a surrounding class `Outer` and a nested class `Inner`. The class `Outer` contains a memberfunction `caller()` which uses the `inner` object that is composed in `Outer` to call the `infunction()` memberfunction of `Inner`:

        class Outer
        {
            public:
                void caller()
                {
                    inner.infunction();
                }
            private:
                class Inner
                {
                    public:
                        void infunction();
                };
                Inner
                    inner;
        };

Also note that the function `Inner::infunction()` can be called as part of the inline definition of `Outer::caller()`, even though the definition of the class `Inner` is yet to be seen by the compiler.

Inline functions can be defined as if they were functions that were defined outside of the class definition: if the function `Outer::caller()` would have been defined outside of the class `Outer`, the full class definition (including the definition of the class `Inner` would have been available to the compiler. In that situation the function is perfectly compilable. Inline functions can be compiled accordingly and there is, e.g., no need to define a special private section in `Outer` in which the class `Inner` is defined before defining the inline function `caller()`.

### 4.8.1: Defining nested class members

Memberfunctions of nested classes may be defined as inline functions. However, they can also be defined outside of their surrounding class. Consider the constructor of the class `FirstWithin` in the example of the previous section. The constructor `FirstWithin()` is defined in the class `FirstWithin`, which is, in turn, defined within the class `Surround`. Consequently, the class scopes of the two classes must be used to define the constructor. E.g.,

        Surround::FirstWithin::FirstWithin()
        {
            variable = 0;
        }

Static (data) members can be defined accordingly. If the class `FirstWithin` would have a `static unsigned` datamember `epoch`, it could be initialized as follows:

        Surround::FirstWithin::epoch = 1970;

Furthermore, both class scopes are needed to refer to public static members in code outside of the surrounding class:

        void showEpoch()
        {
            cout << Surround::FirstWithin::epoch = 1970;
        }

Of course, inside the members of the class `Surround` only the `FirstWithin::` scope needs to be mentioned, and inside the members of the class `FirstWithin` there is no need to refer explicitly to the scope.

What about the members of the class `SecondWithin`? The classes `FirstWithin` and `SecondWithin` are both nested within `Surround`, and can be considered members of the surrounding class. Since members of a class may directy refer to each other, members of the class `SecondWithin` can refer to (public) members of the class `FirstWithin`. Consequently, members of the class `SecondWithin` could refer to the `epoch` member of `FirstWithin` as

`FirstWithin::epoch`

### 4.8.2: Declaring nested classes

Nested classes may be declared before they are actually defined in a surrounding class. Such forward declarations are required if a class contains multiple nested classes, and the nested classes contain pointers to objects of the other nested classes.

For example, the following class `Outer` contains two nested classes `Inner1` and `Inner2`. The class `Inner1` contains a pointer to `Inner2` objects, and `Inner2` contains a pointer to `Inner1` objects. Such cross references require forward declarations:

        class Outer
        {
            ...
            private:
                class Inner2;       // forward declaration

                class Inner1
                {
                    ...
                    private:
                        Inner2
                            *pi2;   // points to Inner2 objects
                };
                class Inner2
                {
                    ...
                    private:
                        Inner1
                            *pi1;   // points to Inner1 objects
                };
                ...
        };

### 4.8.3: Access to private members in nested classes

In order to allow nested classes to access the private members of the surrounding class or to access the private members of other nested classes or to allow the surrounding class to access the private members of nested classes, the `friend` keyword must be used. Consider the following situation, in which a class `Surround` has two nested classes `FirstWithin` and `SecondWithin`, while each class has a static data member `int variable`:

        class Surround
        {
            public:
                class FirstWithin
                {
                    public:
                        int getValue();
                    private:
                        static int
                            variable;
                };
                int getValue();
            private:
                class SecondWithin
                {
                    public:
                        int getValue();
                    private:
                        static int
                            variable;
                };
                static int
                    variable;
        };

If the class `Surround` should be able to access the private members of `FirstWithin` and `SecondWithin`, these latter two classes must declare `Surround` to be their friend. The function `Surround::getValue()` can thereupon access the private members of the nested classes. For example (note the `friend` declarations in the two nested classes):

        class Surround
        {
            public:
                class FirstWithin
                {
                    friend class Surround;
                    public:
                        int getValue();
                    private:
                        static int
                            variable;
                };
                int getValue()
                {
                    FirstWithin::variable = SecondWithin::variable;
                    return (variable);
                }
            private:
                class SecondWithin
                {
                    friend class Surround;
                    public:
                        int getValue();
                    private:
                        static int
                            variable;
                };
                static int
                    variable;
        };

Now, in order to allow the nested classes to access the private members of the surrounding class, the class `Surround` must declare the nested classes as friends. The `friend` keyword may only be used when the class that is to become a friend is already known as a class by the compiler, so either a forward declaration of the nested classes is required, which is followed by the friend declaration, or the friend declaration follows the definition of the nested classes. The forward declaration followed by the friend declaration looks like this:

        class Surround
        {
            class FirstWithin;
            class SecondWithin;
            friend class FirstWithin;
            friend class SecondWithin;

            public:
                class FirstWithin

                ... (etc)

Alternatively, the friend declaration may follow the definition of the classes. Note that a class can be declared a friend following its definition, while the inline code in the definition already uses the fact that it will be declared a friend of the outer class. Also note that the inline code of the nested class uses members of the surrounding class which have not yet been seen by the compiler. Finally note that the variable `variable` that is defined in the class `Surround` is accessed in the nested classes as `Surround::variable`:

        class Surround
        {
            public:
                class FirstWithin
                {
                    friend class Surround;
                    public:
                        int getValue()
                        {
                            Surround::variable = 4;
                            return (variable);
                        }
                    private:
                        static int
                            variable;
                };
                friend class FirstWithin;

                int getValue()
                {
                    FirstWithin::variable = SecondWithin::variable;
                    return (variable);
                }
            private:
                class SecondWithin
                {
                    friend class Surround;
                    public:
                        int getValue()
                        {
                            Surround::variable = 40;
                            return (variable);
                        }
                    private:
                        static int
                            variable;
                };
                friend class SecondWithin;

                static int
                    variable;
        };

Finally, we want to allow the nested classes to access each other's private members. Again this requires some friend declarations. In order to allow `FirstWithin` to access `SecondWithin`'s private members nothing but a friend declaration in `SecondWithin` is required. However, to allow `SecondWithin` to access the private members of `FirstWithin` the `friend class SecondWithin` declaration cannot be plainly given in the class `FirstWithin`, as the definition of `SecondWithin` has not yet been given. A forward declaration of `SecondWithin` is required, and this forward declaration must be given in the class `Surround`, rather than in the class `FirstWithin`. Clearly, the forward declaration `class SecondWithin` in the class `FirstWithin` itself makes no sense, as this would refer to an external (global) class `FirstWithin`. But the attempt to provide the forward declaration of the nested class `SecondWithin` inside `FirstWithin` as `class Surround::SecondWithin` also fails miserably, with the compiler issuing a message like
``Surround' does not have a nested type named `SecondWithin'`
The right procedure to follow here is to declare the class `SecondWithin` in the class `Surround`, before the class `FirstWithin` is defined. Using this procedure, the friend declaration of `SecondWithin` is accepted inside the definition of `FirstWithin`. The following class definition allows full access of the private members of all classes by all other classes:

        class Surround
        {
            class SecondWithin;
            public:
                class FirstWithin
                {
                    friend class Surround;
                    friend class SecondWithin;
                    public:
                        int getValue()
                        {
                            Surround::variable = SecondWithin::variable;
                            return (variable);
                        }
                    private:
                        static int
                            variable;
                };
                friend class FirstWithin;

                int getValue()
                {
                    FirstWithin::variable = SecondWithin::variable;
                    return (variable);
                }
            private:
                class SecondWithin
                {
                    friend class Surround;
                    friend class FirstWithin;
                    public:
                        int getValue()
                        {
                            Surround::variable = FirstWithin::variable;
                            return (variable);
                        }
                    private:
                        static int
                            variable;
                };
                friend class SecondWithin;

                static int
                    variable;
        };

### 4.8.4: Nesting enumerations

Enumerations may also be nested in classes. For example, a class `DataStructure` may be traversed in a forward or backward direction. Such a class can define an enumerator `Traversal` having the values `forward` and `backward`. Furthermore, a memberfunction `setTraversal()` can be defined requiring either of the two enumeration values. The class can be defined as follows:

        class DataStructure
        {
            public:
                enum Traversal
                {
                    forward,
                    backward
                };
                setTraversal(Traversal mode);
                ...
            private:
                Traversal
                    mode;
                ...
        };

Within the class `DataStructure` the values of the `Traversal` enumeration can be used directly. For example:

        void DataStructure::setTraversal(Traversal modeArg)
        {
            mode = modeArg;
            switch (mode)
            {
                forward:
                    ....
                break;

                backward:
                    ....
                break;
            }
        }

Ouside of the class `DataStructure` the name of the enumeration type is not used to refer to the values of the enumeration. Here the classname is enough. Only if a variable of the enumeration type is required the name of the enumeration type is needed, as illustrated by the following piece of code:

        void fun()
        {
            DataStructure::Traversal                // enum typename required
                localMode = DataStructure::forward; // enum typename not required

            DataStructure
                ds;
                                                    // enum typename not required
            ds.setTraversal(DataStructure::backward);
        }

Again, if `DataStructure` would define a nested class `Nested` in which the enumeration `Traversal` would have been defined, the two class scopes would have been required. In that case the former example would have to be coded as follows:

        void fun()
        {
            DataStructure::Nested::Traversal
                localMode = DataStructure::Nested::forward;

            DataStructure
                ds;

            ds.setTraversal(DataStructure::Nested::backward);
        }

- Next chapter
- Previous chapter
- Table of contents