Chapter 6: Classes

Don't hesitate to send in feedback: send an e-mail if you like the C++ Annotations; if you think that important material was omitted; if you find errors or typos in the text or the code examples; or if you just feel like e-mailing. Send your e-mail to Frank B. Brokken.

Please state the document version you're referring to, as found in the title (in this document: 6.2.3) and please state chapter and paragraph name or number you're referring to.

All received mail is processed conscientiously, and received suggestions for improvements will usually have been processed by the time a new version of the Annotations is released. Except for the incidental case I will normally not acknowledge the receipt of suggestions for improvements. Please don't interpret this as me not appreciating your efforts.

In this chapter classes are formally introduced. Two special member functions, the constructor and the destructor, are presented.

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

Let's start by creating 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. A 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:

    #include <string>

    class Person
    {
        std::string d_name;     // name of person
        std::string d_address;  // address field
        std::string d_phone;    // telephone number
        unsigned    d_weight;   // the weight in kg.

        public:                 // interface functions
            void setName(string const &n);
            void setAddress(string const &a);
            void setPhone(string const &p);
            void setWeight(unsigned weight);

            string const &name() const;
            string const &address() const;
            string const &phone() const;
            unsigned weight() const;
    };
It should be noted that this terminology is frequently loosely applied. Sometimes, class definition is used to indicate the class interface. While the class definition (so, the interface) contains the declarations of its members, the actual implementation of these members is also referred to as the definition of these members. As long as the concept of the class interface and the class implementation is well distinguished, it should be clear from the context what is meant by a `definition'.

The data fields in this class are d_name, d_address, d_phone and d_weight. All fields (but d_weight) are string objects. As the data fields are not given a specific access modifier, they are are private, which means that they can only be accessed by the functions of the class Person. Alternatively, the label `private:' might have been used at the beginning of a private section of the class definition.

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., name()). Functions merely returning values stored inside the object, not allowing the caller to modify these internally stored values, are called accessor functions.

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.

A few remarks concerning style. Following Lakos (Lakos, J., 2001) Large-Scale C++ Software Design (Addison-Wesley). I suggest the following setup of class interfaces:

Style conventions usually take a long time to develop. There is nothing obligatory about them, however. I suggest that readers who have compelling reasons not to follow the above style conventions use their own. All others should adopt the above style conventions.

6.1: The constructor

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 destructor's primary task is to return memory allocated by an object to the common pool when an object goes `out of scope'. Allocation of memory is discussed in chapter 7, and destructors will therefore be discussed in depth in that chapter.

In this chapter the emphasis will be on the basic form of the class and on its constructors.

The constructor has by definition the same name as its class. The constructor does not specify a return value, not even void. E.g., for the class Person the constructor is Person::Person(). The C++ run-time system ensures that the constructor of a class, if defined, is called when a variable of the class, called an object, is defined (`created'). It is of course possible to define a class with no constructor at all. In that case the program will call a default constructor when a corresponding object is created. What actually happens in that case depends on the way the class has been defined. The actions of the default constructors are covered in section 6.4.1.

Objects may be defined locally or globally. However, in C++ most objects are defined locally. Globally defined objects are hardly ever required.

When an object is defined locally (in a function), the constructor is called every time the function is called. The object's constructor is then activated at the point where the object 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 defined as a static object (i.e., it is static variable) in a function, the constructor is called when the function in which the static variable is defined is called for the first time.

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

    #include <iostream>
    using namespace std;

    class Demo
    {
        public:
            Demo();
    };

    Demo::Demo()
    {
        cout << "Demo constructor called\n";
    }

    Demo d;

    int main()
    {}

    /*
        Generated output:
    Demo constructor called
    */
The above listing shows how a class Demo is defined which consists of just one function: the constructor. The constructor performs but one action: a message is printed. The program contains one global object of the class Demo, and main() has an empty body. Nonetheless, the program produces some output.

Some important characteristics of constructors are:

6.1.1: A first application

As illustrated at the beginning of this chapter, the class Person contains three private string data members and an unsigned d_weight data member. These data members can be manipulated by the interface functions.

Classes (should) operate as follows:

The set...() functions could be constructed as follows:
    #include "person.h"                 // given earlier

    // interface functions set...()
    void Person::setName(string const &name)
    {
        d_name = name;
    }

    void Person::setAddress(string const &address)
    {
        d_address = address;
    }

    void Person::setPhone(string const &phone)
    {
        d_phone = phone;
    }

    void Person::setWeight(unsigned weight)
    {
        d_weight = weight;
    }

Next the accessor functions are defined. Note the occurence of the keyword const following the parameter lists of these functions: these member functions are called const member functions, indicating that they will not modify their object's data when they're called. Furthermore, notice that the return types of the member functions returning the values of the string data members are string const & types: the const here indicates that the caller of the memberfunction cannot alter the returned value itself. The caller of the accessor member function could copy the returned value to a variable of its own, though, and that variable's value may then of course be modified ad lib. Const member functions are discussed in greater detail in section 6.2. The return value of the weight() member function, however, is a plain unsigned, as this can be a simple copy of the value that's stored in the Person's weight member:

    #include "person.h"                 // given earlier

    // accessor functions ...()
    string const &Person::name() const
    {
        return d_name;
    }

    string const &Person::address() const
    {
       return d_address;
    }

    string const &Person::phone() const
    {
       return d_phone;
    }

    unsigned Person::weight() const
    {
       return d_weight;
    }

The class definition of the Person class given earlier can still be used. The set...() and accessor functions merely implement the member functions declared in that class definition.

The following example shows the use of the class Person. An object is initialized and passed to a function printperson(), which prints the person's data. Note also the usage of the reference operator & in the argument list of the function printperson(). This way only a reference to an existing 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 parameter is declared const.

Alternatively, the function printperson() might have been defined as a public member function of the class Person, rather than a plain, objectless function.

    #include <iostream>
    #include "person.h"                 // given earlier

    void printperson(Person const &p)
    {
        cout << "Name    : " << p.name()     << endl <<
                "Address : " << p.address()  << endl <<
                "Phone   : " << p.phone()    << endl <<
                "Weight  : " << p.weight()   << endl;
    }

    int main()
    {
        Person p;

        p.setName("Linus Torvalds");
        p.setAddress("E-mail: Torvalds@cs.helsinki.fi");
        p.setPhone(" - not sure - ");
        p.setWeight(75);           // kg.

        printperson(p);
        return 0;
    }
/*
    Produced output:

Name    : Linus Torvalds
Address : E-mail: Torvalds@cs.helsinki.fi
Phone   :  - not sure -
Weight  : 75

*/

6.1.2: Constructors: with and without arguments

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

For the class Person a constructor expecting three strings and an unsigned may be handy: these arguments then represent, respectively, the person's name, address, phone number and weight. Such a constructor is:

    Person::Person(string const &name, string const &address,
                    string const &phone, unsigned weight)
    {
        d_name = name;
        d_address = address;
        d_phone = phone;
        d_weight = weight;
    }
The constructor must also be declared in the class interface:
    class Person
    {
        public:
            Person(string const &name, string const &address,
                           string const &phone, unsigned weight);

            // rest of the class interface
    };
However, now that this constructor has been declared, the default constructor must be declared explicitly too, if we still want to be able to construct a plain Person object without any specific initial values for its data members.

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, and the relevant part of the class interface becomes:

    class Person
    {
        public:
            Person();
            Person(string const &name, string const &address,
                           string const &phone, unsigned weight);

            // rest of the class interface
    };
In this case, the Person() constructor doesn't have to do much, as it doesn't have to initialize the string data members of the Person object: as these data members themselves are objects, they are already initialized to empty strings by default. However, there is also an unsigned data member. That member is a variable of a basic type and basic-type variabes are not initialized automatically. So, unless the value of the d_weight data member is explicitly initialized, it will be The 0-value might not be too bad, but normally we don't want a random value for our data members. So, the default constructor has a job to do: initializing the data members which are not initialized to sensible values automatically. Here is an implementation of the default constructor:
    Person::Person()
    {
        d_weight = 0;
    }
The use of a constructor with and without arguments (i.e., the default constructor) is illustrated in the following code fragment. The object a is initialized at its definition using the constructor with arguments, with the b object the default constructor is used:
    int main()
    {
        Person a("Karel", "Rietveldlaan 37", "542 6044", 70);
        Person b;

        return 0;
    }
In this example, the Person objects a and b are created when main() is started: they are local objects, living for as long as the main() function is active.

If Person objects must be contructed using other arguments, other constructors are required as well. It is also possible to define default parameter values. These default parameter values must be given in the class interface, e.g.,

    class Person
    {
        public:
            Person();
            Person(string const &name,
                            string const &address = "--unknown--",
                            string const &phone   = "--unknown--",
                            unsigned weight = 0);

            // rest of the class interface
    };

Often, the constructors are implemented highly similar. This results from the fact that often the constructor's parameters are defined for convenience: a constructor not requiring a phone number but requiring a weight cannot be defined using default arguments, since only the last but one parameter in the constructor defining all four parameters is not required. This cannot be solved using default argument values, but only by defining another constructor, not requiring phone to be specified.

Although some languages (e.g., Java) allow constructors to call constructors, this is conceptually weird. It's weird because it makes a kludge out of the constructor concept. A constructor is meant to construct an object, not to construct itself while it hasn't been constructed yet.

In C++ the way to proceed is as follows: All constructors must initialize their reference data members, or the compiler will (rightfully) complain. This is one of the fundamental reasons why you can't call a constructor during a construction. Next, we have two options:

6.1.2.1: The order of construction The possibility to pass arguments to constructors allows us to monitor the construction of objects during a program's execution. This is shown in the next listing, using a class Test. The program listing below shows a class Test, a global Test object, and two local Test objects: in a function func() and in the main() function. The order of construction is as expected: first global, then main's first local object, then func()'s local object, and then, finally, main()'s second local object:

    #include <iostream>
    #include <string>
    using namespace std;

    class Test
    {
        public:
            Test(string const &name);   // constructor with an argument
    };

    Test::Test(string const &name)
    {
        cout << "Test object " << name << " created" << endl;
    }

    Test globaltest("global");

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

    int main()
    {
        Test first("main first");
        func();
        Test second("main second");
        return 0;
    }
/*
    Generated output:
Test object global created
Test object main first created
Test object func created
Test object main second created
*/

6.2: Const member functions and const objects

The keyword const is often used behind the parameter list of member functions. This keyword indicates that a member function does not alter the data members of its object, but will only inspect them. These member functions are called const member functions. Using the example of the class Person, we see that the accessor functions were declared const:
    class Person
    {
        public:
            std::string const &name() const;
            std::string const &address() const;
            std::string const &phone() const;
    };
This fragment illustrates that the keyword const appears behind the functions' argument lists. Note that in this situation the rule of thumb given in section 3.1.3 applies as well: whichever appears before the keyword const, may not be altered and doesn't alter (its own) data.

The const specification must be repeated in the definitions of member functions:

    string const &Person::name() const
    {
        return d_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
    d_name = 0;
in the above const function name() would result in a compilation error.

Const member functions exist because C++ allows const objects to be created, or (used more often) references to const objects to be passed 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 const variable is created, but subsequent assignments cannot take place.

The following example shows the definition of a const object of the class Person. 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", "f.b.brokken@rc.rug.nl", "363 9281");

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. As a rule of thumb it is stated here that member functions should always be given the const attribute, unless they actually modify the object's data.

Earlier, in section 2.5.11 the concept of function overloading was introduced. There it noted that member functions may be overloaded merely by their const attribute. In those cases, the compiler will use the member function matching most closely the const-qualification of the object:

An example showing the selection of (non) const member functions is given in the following example:
    #include <iostream>
    using namespace std;

    class X
    {
        public:
            X();
            void member();
            void member() const;
    };

    X::X()
    {}
    void X::member()
    {
        cout << "non const member\n";
    }
    void X::member() const
    {
        cout << "const member\n";
    }

    int main()
    {
        X const constObject;
        X       nonConstObject;

        constObject.member();
        nonConstObject.member();
    }
    /*
            Generated output:

        const member
        non const member
    */
Overloading member functions by their const attribute commonly occurs in the context of operator overloading. See chapter 9, in particular section 9.1 for details.

6.3: The keyword `inline'

Let us take another look at the implementation of the function Person::name():
    string const &Person::name() const
    {
        return d_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");

    cout << frank.name();
the following actions take place:

Especially the first part of these actions results in some time loss, since an extra function call is necessary to retrieve the value of the name field. Sometimes a faster procedure may be desirable, in which the name field becomes immediately available, without ever actually calling a function name(). This can be realized using inline functions.

6.3.1: Inline functions within class interfaces

Inline functions may be implemented in the class interface itself. For the class Person this results in the following implementation of name():
    class Person
    {
        public:
            string const &name() const
            {
                return d_name;
            }
    };
Note that the inline code of the function name() now literally occurs inline 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 are fully defined within the class interface.

This has the following effect: Whenever name() is called in a program statement, the compiler may generate the code in the function's body at the location of the function call. The function itself may never actually be called. Consequently, the function call is prevented, but the function's body appears as often in the final program as the inline function is actually called.

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 multiple occurrences of the function's code: one copy for each invocation 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. The compiler knows this too, and considers the use of inline functions a request rather than a command: if the compiler considers the function too long, it will not grant the request, but will, instead, treat the function as a normal function.

6.3.2: Inline functions outside of class interfaces

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:
            string const &name() const;
    };

    inline string const &Person::name() const
    {
        return d_name;
    }
Again, the compiler will insert the code of the function name() instead of generating a call.

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.

6.3.3: When to use inline functions

When should inline functions be used, and when not? There are some rules of thumb which may be followed: 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 once again that the keyword inline is not really a command to the compiler. Rather, it is a request the compiler may or may not grant.

6.4: Objects inside objects: composition

Often objects are used as data members in class definitions. This is called composition.

For example, the class Person holds information about the name, address and phone number. This information is stored in string data members, which are themselves objects: composition.

Composition is not extraordinary or C++ specific: in C a struct or union field is commonly used in other compound types.

The initialization of composed objects deserves some special attention: the topics of the coming sections.

6.4.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 a specific constructor of the composing class. This is illustrated below for the class Person. In this fragment it assumed that a constructor for a Person should be defined expecting four arguments: the name, address and phone number plus the person's weight:

    Person::Person(char const *name, char const *address,
                    char const *phone, unsigned weight)
    :
        d_name(name),
        d_address(address),
        d_phone(phone),
        d_weight(weight)
    {}
Following the argument list of the constructor Person::Person(), the constructors of the string data members are explicitly called, e.g., name(mn). The initialization takes place before the code block of Person::Person() (now empty) is executed. This construction, where member initialization takes place before the code block itself is executed is called member initialization. Member initialization can be made explicit in the member initializer list, that may appear after the parameter list, between a colon (announcing the start of the member initializer list) and the opening curly brace of the code block of the constructor.

Member initialization always occurs when objects are composed in classes: if no constructors are mentioned in the member initializer list the default constructors of the objects are called. Note that this only holds true for objects. Data members of primitive data types are not initialized automatically.

Member initialization can, however, also be used for primitive data members, like int and double. The above example shows the initialization of the data member weight from the parameter weight. For further illustration, we used the same identifiers here: with member initialization there is no ambiguity and the first (left) identifier in weight(weight) is always interpreted as the data member to be initialized, whereas the identifier between parentheses is interpreted as the parameter.

When a class has multiple composed data members, all members can be initialized using a `member initializer list': this list consists of the constructors of all composed objects, separated by commas. The order in which the objects are initialized is defined by the order in which the members are defined in the class interface. If the order of the initialization in the constructor differs from the order in the class interface, the compiler complains, and reorders the initialization so as to match the order of the class interface.

Member initializers should be used as often as possible: it can be downright necessary to use them, and not using member initializers can result in inefficient code: with objects always at least the default constructor is called. So, in the following example, first the string members are initialized to empty strings, whereafter these values are immediately redefined to their intended values. Of course, the immediate initialization to the intended values would have been more efficent.

    Person::Person(char const *name, char const *address,
                    char const *phone, unsigned weight)
    {
        d_name = name;
        d_address = address;
        d_phone = phone;
        d_weight = weight;
    }
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 too much.

This means that when the definition of a Person is altered so as to contain a string const birthday member, the implementation of the constructor Person::Person() in which also the birthday must be initialized, a member initializer must be used for birthday. Direct assignment of the birthday would be illegal, since birthday is a const data member. The next example illustrates the const data member initialization:

    Person::Person(char const *name, char const *address,
                    char const *phone, char const *birthday,
                    unsigned weight)
    :
        d_name(name),
        d_address(address),
        d_phone(phone),
        d_birthday(birthday),       // assume: string const d_birthday
        d_weight(weight)
    {}
Concluding, the rule of thumb is the following: when composition of objects is used, the member initializer method is preferred to explicit initialization of composed objects. This not only results in more efficient code, but it also allows composed objects to be declared as const objects.

6.4.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?

However, the following construction will not result in the initialization of the Configfile &d_conf reference data member:
    Process::Process(Configfile &conf)
    {
        d_conf = conf;        // wrong: no assignment
    }
The statement d_conf = 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 (d_conf). 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 d_conf refer? To no variable, since we haven't initialized d_conf. After all, the whole purpose of the statement d_conf = conf was to initialize d_conf....

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

    Process::Process(Configfile &conf)
    :
        d_conf(conf)      // initializing reference member
    {}
Note that this syntax can be used in all cases where reference data members are used. If d_ir would be an int reference data member, a construction like
    Process::Process(int &ir)
    :
        d_ir(ir)
    {}
would have been called for.

6.5: Header file organization

In section 2.5.9 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 member functions of classes. With source files there are basically two approaches:

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 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 frequently has 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, as a starting point 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 (e.g., /usr/local/include/myheaders/).

If a class MyClass is developed there, create a subdirectory (or subdirectory link) myheaders of one of the standard 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 <myheaders/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.

Assume the File class has a member gets(String &destination), while the class String has a member function getLine(File &file). 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 the source file of the function File::gets() proceeds as follows: The solution for this problem is to use a forward class reference before the class interface, and to include the corresponding class header file after the class interface. 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
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 classes are involved and with (non-inline) member functions having class-type return values or parameters.

Note that this setup doesn't work with composition, nor with inline member functions. Assume the class File has a composed data member of the class String. In that case, the class interface of the class File must include the header file of the class String before the class interface 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 interface of the File class is completed.

In cases where classes contain composed objects (or are derived from other classes, see chapter 13) the header files of the classes of the composed objects must have been read before the class interface 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
    {
        String d_line;              // composition !

        public:
            void gets(String &string);
    };
    #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 remaining header files (appearing below the class interface itself) are required only because they are used by the class' source files.

This approach allows us to introduce yet another refinement:

6.5.1: Using namespaces in header files

When entities from namespaces are used in header files, in general using directives should not be used in these header files if they are to be used as general header files declaring classes or other entities from a library. When the using directive is used in a header file then users of such a header file are forced to accept and use the declarations in all code that includes the particular header file.

For example, if in a namespace special an object Inserter cout is declared, then special::cout is of course a different object than std::cout. Now, if a class Flaw is constructed, in which the constructor expects a reference to a special::Inserter, then the class should be constructed as follows:

    class special::Inserter;

    class Flaw
    {
    public:
        Flaw(special::Inserter &ins);
    };
Now the person designing the class Flaw may be in a lazy mood, and might get bored by continuously having to prefix special:: before every entity from that namespace. So, the following construction is used:
    using namespace special;

    class Inserter;

    class Flaw
    {
    public:
        Flaw(Inserter &ins);
    };
This works fine, up to the point where somebody want to include flaw.h in other source files: because of the using directive, this latter person is now by implication also using namespace special, which could produce unwanted or unexpected effects:
    #include <flaw.h>
    #include <iostream>

    using std::cout;

    int main()
    {
        cout << "starting" << endl;     // doesn't compile
    }
The compiler is confronted with two interpretations for cout: first, because of the using directive in the flaw.h header file, it considers cout a special::Extractor, then, because of the using directive in the user program, it considers cout a std::ostream. As compilers do, when confronted with an ambiguity, an error is reported.

As a rule of thumb, header files intented to be generally used should not contain using declarations. This rule does not hold true for header files which are included only by the sources of a class: here the programmer is free to apply as many using declarations as desired, as these directives never reach other sources.

6.6: The keyword `mutable'

Earlier, in section 6.2, the concepts of const member functions and const objects were introduced.

C++, however, allows the construction of objects which are, in a sense, neither const objects, nor non-const objects. Data members which are defined using the keyword mutable, can be modified by const member functions.

An example of a situation where mutable might come in handy is where a const object would want to register the number of times it was used. A simple class allowing just, as well as an example in which a const object of the class Mutable that could be:

#include <string>
#include <iostream>
#include <memory>


class Mutable
{
    std::string d_name;
    mutable int d_count;                // uses mutable keyword

    public:
        Mutable(std::string const &name)
        :
            d_name(name),
            d_count(0)
        {}

        void called() const
        {
            std::cout << "Calling " << d_name <<
                                    " (attempt " << ++d_count << ")\n";
        }
};


int main()
{
    Mutable const x("Constant mutable object");

    for (int idx = 0; idx < 4; idx++)
        x.called();                     // modify data of const object
}

/*
    Generated output:

    Calling Constant mutable object (attempt 1)
    Calling Constant mutable object (attempt 2)
    Calling Constant mutable object (attempt 3)
    Calling Constant mutable object (attempt 4)
*/

The keyword mutable may also be useful in classes implementing, e.g., reference counting. Consider a class implementing reference counting for textstrings. The object doing the reference counting might be a const object, but the class may define a copy constructor. Since const objects can't be modified, how would the copy constructor be able to increment the reference count? Here the mutable keyword may profitably be used, as it can be incremented and decremented, even though its object is a const object.

The advantage of having a mutable keyword is of that, in the end, the programmer decides which data members can be modified and which data members can't. But that might as well be a disadvantage: having the keyword mutable around prevents us from making rigid assumptions about the stability of const objects. Depending on the context, that may or may not be a problem. In practice, mutable tends to be useful only for internal bookkeeping purposes: accessors returning values of mutable data members might return puzzling results to clients using these accessors with const objects. In those situations, the nature of the returned value should clearly be documented. As a rule of thumb: do not use mutable unless there is a very clear reason to divert from this rule.