Chapter 7: 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: 8.3.1) 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 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 a class Person right away. From the onset, it is important to make the distinction between the class interface and its implementation. A class may loosely be defined as `a set of data and all the functions operating on those data'. This definition will be refined later but for now it is sufficient to get us started.

A class interface is a definition, defining the organization of objects of that class. Normally a definition results in memory reservation. E.g., when defining int variable the compiler will make sure that some memory will be reserved in the final program storing variable's values. Although it is a definition no memory is set aside by the compiler once it has processed the class definition. But a class definition follows the one definition rule: in C++ entities may be defined only once. As a class definition does not imply that memory is being reserved the term class interface is preferred instead.

Class interfaces are normally contained in a class header file, e.g., person.h. We'll start our class Person interface here:

    #include <string>

    class Person
    {
        std::string d_name;         // name of person
        std::string d_address;      // address field
        std::string d_phone;        // telephone number
        size_t      d_mass;         // the mass in kg.

        public:                     // member functions
            void setName(std::string const &name);
            void setAddress(std::string const &address);
            void setPhone(std::string const &phone);
            void setMass(size_t mass);

            std::string const &name()    const;
            std::string const &address() const;
            std::string const &phone()   const;
            size_t mass()                const;
    };
The member functions that are declared in the interface must still be implemented. The implementation of these members is properly called their definition.

In addition to the member function a class defines the data manipulated by the member functions. These data are called the data members. In Person they are d_name, d_address, d_phone and d_mass. Data members should be given private access rights. Since the class uses private access rights by default they may simply be listed at the top of the interface.

All communication between the outer world and the class data is routed through the class's member functions. Data members may receive new values (e.g., using setName) or they may be retrieved for inspection (e.g., using name). Functions merely returning values stored inside the object, not allowing the caller to modify these internally stored values, are called accessors.

Syntactically there is only a marginal difference between a class and a struct. Classes by default define private members, structs define public members. Conceptually, though, there are differences. In C++ structs are used in the way they are used in C: to aggregate data, which are all freely accessible. Classes, on the other hand, hide their data from access by the outside world (which is aptly called data hiding) and offer member functions to define the communication between the outer world and the class's data members.

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, though. I suggest that readers who have compelling reasons not to follow the above style conventions use their own. All others are strongly advised to adopt the above style conventions.

Finally, referring back to section 3.1.1 that

    using namespace std;
must be used in most (if not all) examples of source code. As will be explained in sections 7.9 and 7.9.1 the using directive should follow the preprocessor directive(s) including the header files, using a setup like the following:
    #include <iostream>
    #include "person.h"

    using namespace std;

    int main()
    {
        ...
    }

7.1: The constructor

C++ classes may contain two special categories of member functions which are essential to the proper working of the class. These categories are the constructors and 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 8, and destructors will therefore be discussed in depth in that chapter. In this chapter the emphasis will be on the class's organization and its constructors.

Constructor are recognized by their names which is equal to the class name. Constructors do not specify return values, not even void. E.g., the class Person may define a constructor Person::Person(). The C++ run-time system ensures that the constructor of a class is called when a variable of the class is defined. It is possible to define a class lacking any constructor. In that case the compiler will define a default constructor that is called when an object of that class is defined. What actually happens in that case depends on the data members that are defined by that class (cf. section 7.2.1).

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

When a local object is defined its constructor is called every time the function is called. The object's constructor is activated at the point where the object is defined (a subtlety is that an object may be defined implicitly as, e.g., a temporary variable in an expression).

When an object is defined as a static object is called when the program starts. In this case the constructor is called even before the function main starts. Example:

    #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 program contains one global object of the class Demo with main having an empty body. Nonetheless, the program produces some output generated by the constructor of the globally defined Demo object.

Constructors have a very important and well-defined role. They must ensure that all the class's data members have sensible or at least well-defined values once the object has been constructed. We'll get back to this important task shortly. The default constructor has no argument. It is defined by the compiler unless another constructor is defined and unless its definition is suppressed (cf. section 7.4). If a default constructor is required in addition to another constructor then the default constructor must explicitly be defined as well. The C++0x standard provides special syntax to do that as well, which is also covered by section 7.4.

7.1.1: A first application

Our example class Person has three string data members and a size_t d_mass data member. Access to these data members is controlled by interface functions.

Whenever an object is defined the class's constructor(s) ensure that its data members are given `sensible' values. Thus, objects never suffer from uninitialized values. Data members may be given new values, but that should never be directly allowed. It is a core principle (called data hiding) of good class design that its data members are private. The modification of data members is therefore fully controlled by member functions and thus, indirectly, by the class-designer. The class encapsulates all actions performed on its data members and due to this encapsulation the class object may assume the `responsibility' for its own data-integrity. Here is a minimal definition of Person's manipulating members:

    #include "person.h"                 // given earlier

    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::setMass(size_t mass)
    {
        d_mass = mass;
    }
It's a minimal definition in that no checks are performed. But it should be clear that checks are easy to implement. E.g., to ensure that a phone number only contains digits one could define:
    void Person::setPhone(string const &phone)
    {
        if (phone.find_first_not_of("0123456789") == string::npos)
            d_phone = phone;
        else
            cout << "A phone number may only contain digits\n";
    }
Similarly, access to the data members is controlled by encapsulating accessor members. Accessors ensure that data members cannot suffer from uncontrolled modifications. Since accessors conceptually do not modify the object's data (but only retrieve the data) these member functions are given the predicate const. They are called const member functions, which, as they are guaranteed not to modify their object's data, are available to both modifiable and constant objects (cf. section 7.5).

To prevent backdoors we must also make sure that the data member is not modifiable through an accessor's return value. For values of built-in primitive types that's easy, as they are usually returned by value, which are copies of the values found in variables. But since objects may be fairly large making copies are usually prevented by returning objects by reference. A backdoor is created by returning a data member by reference, as in the following example, showing the allowed abuse below the function definition:

    string &Person::name() const
    {
        return d_name;
    }

    Person somebody;
    somebody.setName("Nemo");

    somebody.name() = "Eve";    // Oops, backdoor changing the name
To prevent the backdoor objects are returned as const references from accessors. Here are the implementations of Person's accessors:
    #include "person.h"                 // given earlier

    string const &Person::name() const
    {
        return d_name;
    }
    string const &Person::address() const
    {
       return d_address;
    }
    string const &Person::phone() const
    {
       return d_phone;
    }
    size_t Person::mass() const
    {
       return d_mass;
    }

The Person class interface remains the starting point for the class design: its member functions define what can be asked of a Person object. In the end the implementation of its members merely is a technicality allowing Person objects to do their jobs.

The next example shows how the class Person may be used. An object is initialized and passed to a function printperson(), printing the person's data. Note the reference operator in the parameter list of the function printperson. Only a reference to an existing Person object is passed to the function, rather than a complete object. The fact that printperson does not modify its argument is evident from the fact that the parameter is declared const.

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

    void printperson(Person const &p)
    {
        cout << "Name    : " << p.name()     << "\n"
                "Address : " << p.address()  << "\n"
                "Phone   : " << p.phone()    << "\n"
                "Mass  : " << p.mass()   << '\n';
    }

    int main()
    {
        Person p;

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

        printperson(p);
    }
/*
    Produced output:

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

*/

7.1.2: Constructors: with and without arguments

The class Person's constructor so far has no parameters. C++ allows constructors to be defined with or without parameter lists. The arguments are supplied when an object is defined.

For the class Person a constructor expecting three strings and a size_t might be useful. Representing, respectively, the person's name, address, phone number and mass. This constructor is:

    Person::Person(string const &name, string const &address,
                   string const &phone, size_t mass)
    {
        d_name = name;
        d_address = address;
        d_phone = phone;
        d_mass = mass;
    }
It must of course also be declared in the class interface:
    class Person
    {
        // data members (not altered)

        public:
            Person(std::string const &name, std::string const &address,
                   std::string const &phone, size_t mass);

            // rest of the class interface (not altered)
    };
Now that this constructor has been declared, the default constructor must explicitly be declared as well if we still want to be able to construct a plain Person object without any specific initial values for its data members. The class Person would thus support two constructors, and the part declaring the constructors now becomes:
    class Person
    {
        // data members
        public:
            Person();
            Person(std::string const &name, std::string const &address,
                   std::string const &phone, size_t mass);

            // additional members
    };
In this case, the default constructor doesn't have to do very much, as it doesn't have to initialize the string data members of the Person object. As these data members are objects themselves, they are initialized to empty strings by their own default constructor. However, there is also a size_t data member. That member is a variable of a built-in type and such variabes do not have constructors and so are not initialized automatically. Therefore, unless the value of the d_mass 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, even the default constructor has a job to do: initializing the data members which are not initialized to sensible values automatically. Its implementation can be:
    Person::Person()
    {
        d_mass = 0;
    }
Using constructors with and without arguments is illustrated next. The object karel is initialized by the constructor defining a non-empty parameter list while the default constructor is used with the anon object:
    int main()
    {
        Person karel("Karel", "Rietveldlaan 37", "542 6044", 70);
        Person anon;
    }
The two Person objects are defined when main starts as they are local objects, living only for as long as main is active.

If Person objects must be definable using other arguments, corresponding constructors must be added to Person's interface. Apart from overloading class constructors it is also possible to provide constructors with default argument values. These default arguments must be specified with the constructor declarations in the class interface, like so:

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

    };
Often, constructors use highly similar implementions. This results from the fact that the constructor's parameters are often defined for convenience: a constructor not requiring a phone number but requiring a mass cannot be defined using default arguments, since phone is not the constructor's last parameter. Consequently a special constructor is required not having phone in its parameter list.

In pre C++0x C++ this situation is commonly tackled as follows: all constructors must initialize their reference and const data members, or the compiler will (rightfully) complain. To initialize the remaining members (non-const and non-reference members) we have two options:

C++0x allows constructors to call each other. This is illustrated in section 7.2.3 below.

7.1.2.1: The order of construction

The possibility to pass arguments to constructors allows us to monitor the construction order of objects during program execution. This is illustrated by the next program using a class Test. The program defines a global Test object and two local Test objects. 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" << '\n';
    }

    Test globaltest("global");

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

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

7.2: Objects inside objects: composition

In the class Person objects are used as data members. This construction technique is called composition.

Composition is neither extraordinary nor C++ specific: in C a struct or union field is commonly used in other compound types. In C++ it requires some special thought as their initialization sometimes is subject to restrictions, as discussed in the next few sections.

7.2.1: Composition and const objects: const member initializers

Unless specified otherwise object data members of classes are initialized by their default constructors. Using the default constructor might not always be the optimal way to intialize an object and it might not even be possible: a class might simply not define a default constructor.

Earlier we've encountered the following constructor of the Person:

    Person::Person(string const &name, string const &address,
                   string const &phone, size_t mass)
    {
        d_name = name;
        d_address = address;
        d_phone = phone;
        d_mass = mass;
    }
Think briefly about what is going on in this constructor. In the constructor's body we encounter assignments to string objects. Since assignments are used in the constructor's body their left-hand side objects must exist. But when objects are coming into existence constructors must have been called. The initialization of those objects is thereupon immediately undone by the body of Person's constructor. That is not only inefficient but sometimes downright impossible. Assume that the class interface mentions a string const data member: a data member whose value is not supposed to change at all (like a birthday, which usually doesn't change very much and is therefore a good candidate for a string const data member). Constructing a birthday object and providing it with an initial value is OK, but changing the initial value isn't.

The body of a constructor allows assignments to data members. The initialization of data members happens before that. C++ defines the member initializer syntax allowing us to specify the way data members are initialized at construction time. Member initializers are specified as a list of constructor specifications between a colon following a constructor's parameter list and the opening curly brace of a constructor's body, as follows:

    Person::Person(string const &name, string const &address,
                   string const &phone, size_t mass)
    :
        d_name(name),
        d_address(address),
        d_phone(phone),
        d_mass(mass)
    {}
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 d_mass from the parameter mass. When member initializers are used the data member could even have the same name as the constructor's parameter (although this is deprecated) as there is no ambiguity and the first (left) identifier used in a member initializer is always a data member that is initialized whereas the identifier between parentheses is interpreted as the parameter.

The order in which class type data members are initialized is defined by the order in which those members are defined in the composing 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. As shown it may be required to use them (e.g., to initialize const data members, or to initialize objects of classes lacking default constructors) but not using member initializers also results in inefficient code as the default constructor of a data member is always automatically called unless an explicit member initializer is specified. Reassignment in the constructor's body following default construction is then clearly inefficient. Of course, sometimes it is fine to use the default constructor, but in those cases the explicit member initializer can be omitted.

As a rule of thumb: if a value is assigned to a data member in the constructor's body then try to avoid that assignment in favor of using a member initializer.

7.2.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 another object used in 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?

But a reference variable cannot be initialized using an assignment, and so the following is incorrect:
    Process::Process(Configfile &conf)
    {
        d_conf = conf;        // wrong: no assignment
    }
The statement d_conf = conf fails, because it is not an initialization, but an assignment of one Configfile object (i.e., conf), to another (d_conf). An assignment to a reference variable is actually an assignment to the variable the reference variable refers to. But which variable does d_conf refer to? To no variable at all, since we haven't initialized d_conf. After all, the whole purpose of the statement d_conf = conf was to initialize d_conf....

How to initialize d_conf? We once again use the member initializer syntax. Here is the correct way to initialize d_conf:

    Process::Process(Configfile &conf)
    :
        d_conf(conf)      // initializing reference member
    {}
The above syntax must be used in all cases where reference data members are used. E.g., if d_ir would have been an int reference data member, a construction like
    Process::Process(int &ir)
    :
        d_ir(ir)
    {}
would have been required.

7.2.3: Constructors calling constructors (C++0x, ?)

Often constructors are specializations of each other, allowing objects to be constructed using subsets of arguments for its data members, and/or using default argument values for other data members. In many cases classes define initialization members that are called by the various constructors. Here is an example. A class Stat is designed as a wrapper class around C's stat function. It might define three constructors: one expecting no arguments and initializing all data members to appropriate values; a second one doing the same, but it calls stat with the filename provided to the constructor and a third one expecting a filename and a search path for the provided file name. Rather than repeating the initialization code in each constructor, the common code can be factorized into a member init() which is thereupon called by the constructors.

The C++0x standard offers an alternative to this design by allowing constructors to call each other. The C++0x standard allows constructors to call each other as shown in the following example:

    class Stat
    {
        public:
            Stat()
            :
                // default initialization of members
            {}
            Stat(std::string const &fileName)
            :
                Stat()
            {
                set(fileName);
            }
            Stat(std::string const &fileName, std::string const &searchPath)
            :
                Stat()
            {
                set(fileName, searchPath);
            }
            ...
    };
There is one caveat: C++ considers the object as fully constructed once a constructor has normally finished. Once a constructor has finished the class's destructor is guaranteed to be called (cf. chapter 8) and so remaining code must make sure that, e.g., all the class's pointer data members remain in a valid state. Also, as a prelude to chapter 9, realize that a destructor will be called if a constructor throws an exception after having completed the call to another constructor.

C++ allows static const integral data members to be initialized within the class interfaces (cf. chapter 11). The C++0x standard adds to this the facility to provide all data members (const or non-const, integral or non-integral) with a default initialization that is specified by the class interface.

These default initializations may be overruled by constructors. E.g., if the class Stat uses a data member bool d_hasPath which is false by default but the third constructor (see above) should initialize it to true then the following approach is possible:

    class Stat
    {
        bool d_hasPath = false;

        public:
            Stat(std::string const &fileName, std::string const &searchPath)
            :
                d_hasPath(true)     // overrule the interface-specified
                                    // value
            {}
    };
Here d_hasPath receives its value only once: it's always initialized to false except when the shown constructor is used in which case it is initialized to true.

7.3: Uniform initialization (C++0x)

When defining variables and objects they may immediately be given initial values. Class type objects are always initialized using one of their available constructors. C already supports the array and struct initializer list consisting of a list of constant expressions surrounded by a pair of curly braces. A comparable initialization, called uniform initialization is added to C++ by the C++0x standard. It uses the following syntax:
    Type object {value list};
When defining objects using a list of objects each individual object may use its own uniform initialization.

The advantage of uniform initialization over using constructors is that using constructor arguments may sometimes result in an ambiguity as constructing an object may sometimes be confused with using the object's overloaded function call operator (cf. section 10.10). As initializer lists can only be used with plain old data (POD) types (cf. section 8.8) and with classes that are `initializer list aware' (like std::vector) the ambiguity does not arise when initializer lists are used.

Uniform initialization can be used to initialize an object or variable, but also to initialize data members in a constructor or implicitly in the return statement of functions. Examples:

    class Person
    {
        // data members
        public:
            Person(std::string const &name, size_t mass)
            :
                d_name {name},
                d_mass {mass}
            {}

            Person copy() const
            {
                return {d_name, d_mass};
            }
    };
Although the uniform intialization syntax is slightly different from the syntax of an initializer list (the latter using the assignment operator) the compiler nevertheless uses the initializer list if a constructor supporting an initializer list is available. As an example consider:
    class Vector
    {
        public:
            Vector(size_t size);
            Vector(std::initializer_list<int> const &values);
    };

    Vector vi = {4};
When defining vi the constructor expecting the initializer list is called rather than the constructor expecting a size_t argument. If the latter constructor is required the definition using the standard constructor syntax must be used. I.e., Vector vi(4).

Initializer lists are themselves objects that may be constructed using another initializer list. However, values stored in an initializer list are immutable. Once the initializer list has been defined their values remain as-is. Initializer lists support a basic set of member functions and constructors:

7.4: Defaulted and deleted class members (C++0x)

In everyday class design two situations are frequently encountered: Once a class defines at least one constructor its default constructor is not automatically defined by the compiler. The C++0x standard relaxes that restriction somewhat by offering the ` = default' syntax. A class specifying `= default' with its default constructor declaration indicates that the trivial default constructor should be provided by the compiler. A trivial default constructor performs the following actions: Trivial implementations can also be provided for the copy constructor, the overloaded assignment operator, and the destructor. Those members are introduced in chapter 8.

Conversely, situations exist where some (otherwise automatically provided) members should not be made available. This is realized by specifying ` = delete'. Using = default and = delete is illustrated by the following example. The default constructor receives its trivial implementation, copy-construction is prevented:

    class Strings
    {
        public:
            Strings() = default;
            Strings(std::string const *sp, size_t size);

            Strings(Strings const &other) = delete;
    };

7.5: 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. Such member functions are called const member functions. In 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;
            size_t mass()              const;
    };
The rule of thumb given in section 3.1.3 applies here too: whichever appears to the left of the keyword const, is not altered. With member functions this should be interpreted as `doesn't alter its own data'.

When implementing a const member function the const attribute must be repeated:

    string const &Person::name() const
    {
        return d_name;
    }
The compiler will prevent the data members of a class from being modified by one of its const member functions. Therefore a statement like
    d_name[0] = toupper(static_cast<unsigned char>(d_name[0]));
results in a compiler error when added to the above function's definition.

Const member functions are used to prevent inadvertent data modification. Except for constructors and the destructor (cf. chapter 8) only const member functions can be used with (plain, references or pointers to) const objects.

Const objects are frequently encounterd as const & parameters of functions. Inside such functions only the object's const members may be used. Here is an example:

    void displayMass(ostream &out, Person const &person)
    {
        out << person.name() << " weighs " << person.mass() << " kg.\n";
    }
Since person is defined as a Person const & the function displayMass cannot call, e.g.,
person.setMass(75).

The const member function attribute can be used to overload member functions. When functions are overloaded by their const attribute the compiler will use the member function matching most closely the const-qualification of the object:

The next example illustrates how (non) const member functions are selected:
    #include <iostream>
    using namespace std;

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

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

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

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

        const member
        non const member
    */
As a general principle of design: member functions should always be given the const attribute, unless they actually modify the object's data.

7.5.1: Anonymous objects

Sometimes objects are used because they offer a certain functionality. The objects only exist because of their functionality, and nothing in the objects themselves is ever changed. The following class Print offers a facility to print a string, using a configurable prefix and suffix. A partial class interface could be:
    class Print
    {
        public:
            Print(ostream &out);
            print(std::string const &prefix, std::string const &text,
                     std::string const &suffix) const;
    };
An interface like this would allow us to do things like:
    Print print(cout);
    for (int idx = 0; idx < argc; ++idx)
        print.print("arg: ", argv[idx], "\n");
This works fine, but it could greatly be improved if we could pass print's invariant arguments to Print's constructor. This would simplify print's prototype (only one argument would need to be passed rather than three) and we could wrap the above code in a function expecting a Print object:
    void allArgs(Print const &print, int argc, char *argv[])
    {
        for (int idx = 0; idx < argc; ++idx)
            print.print(argv[idx]);
    }
The above is a fairly generic piece of code, at least it is with respect to Print. Since prefix and suffix don't change they can be passed to the constructor which could be given the prototype:
    Print(ostream &out, string const &prefix = "", string const &suffix = "");
Now allArgs may be used as follows:
    Print p1(cout, "arg: ", "\n");      // prints to cout
    Print p2(cerr, "err: --", "--\n");  // prints to cerr

    allArgs(p1, argc, argv);            // prints to cout
    allArgs(p2, argc, argv);            // prints to cerr
But now we note that p1 and p2 are only used inside the allArgs function. Furthermore, as we can see from print's prototype, print doesn't modify the internal data of the Print object it is using.

In such situations it is actually not necessary to define objects before they are used. Instead anonymous objects may be used. Anonymous objects can be used:

These anonymous objects are considered constant as they merely exist for passing the information of (class type) objects to functions. They are not considered 'variables'. Of course, a const_cast could be used to cast away the const reference's constness, but any change will be lost when the function returns. These anonymous objects used to initialize const references should not be confused with rvalue references (section 3.3.2) which have a completely different purpose in life. Rvalue references primarily exist to be `swallowed' by functions receiving them. Thus, the information made available by rvalue references outlives the rvalue reference objects which are also anonymous.

Anonymous objects are defined when a constructor is used without providing a name for the constructed object. Here is the corresponding example:

    allArgs(Print(cout, "arg: ", "\n"), argc, argv);    // prints to cout
    allArgs(Print(cerr, "err: --", "--\n"), argc, argv);// prints to cerr
In this situation the Print objects are constructed and immediately passed as first arguments to the allArgs functions, where they are accessible as the function's print parameter. While the allArgs function is executing they can be used, but once the function has completed, the anonymous Print objects are no longer accessible.

7.5.1.1: Subtleties with anonymous objects

Anonymous objects can be used to initialize function parameters that are const references to objects. These objects are created just before such a function is called, and are destroyed once the function has terminated. C++'s grammar allows us to use anonymous objects in other situations as well. Consider the following snippet of code:
    int main()
    {
        // initial statements
        Print("hello", "world");
        // later statements
    }
In this example an anonymous Print object is constructed, and it is immediately destroyed thereafter. So, following the `initial statements' our Print object is constructed. Then it is destroyed again followed by the execution of the `later statements'.

The example illustrates that the standard lifetime rules do not apply to anonymous objects. Their lifetimes are limited to the statements, rather than to the end of the block in which they are defined.

Plain anonymous object are at least useful in one situation. Assume we want to put markers in our code producing some output when the program's execution reaches a certain point. An object's constructor could be implemented so as to provide that marker-functionality allowing us to put markers in our code by defining anonymous, rather than named objects.

C++'s grammar contains another remarkable characteristic illustrated by the next example:

    int main(int argc, char **argv)
    {
        Print p(cout, "", "");              // 1
        allArgs(Print(p), argc, argv);      // 2
    }
In this example a non-anonymous object p is constructed in statement 1, which is then used in statement 2 to initialize an anonymous object. The anonymous object, in turn, is then used to initialize allArgs's const reference parameter. This use of an existing object to initialize another object is common practice, and is based on the existence of a so-called copy constructor. A copy constructor creates an object (as it is a constructor) using an existing object's characteristics to initialize the data of the object that's created. Copy constructors are discussed in depth in chapter 8, but presently only the concept of a copy constructor is used.

In the above example a copy constructor is used to initialize an anonymous object. The anonymous object was then used to initialize a parameter of a function. However, when we try to apply the same trick (i.e., using an existing object to initialize an anonymous object) to a plain statement, the compiler generates an error: the object p can't be redefined (in statement 3, below):

    int main(int argc, char *argv[])
    {
        Print p("", "");                    // 1
        allArgs(Print(p), argc, argv);      // 2
        Print(p);                           // 3 error!
    }
Does this mean that using an existing object to initialize an anonymous object that is used as function argument is OK, while an existing object can't be used to initialize an anonymous object in a plain statement?

The compiler actually provides us with the answer to this apparent contradiction. About statement 3 the compiler reports something like:

    error: redeclaration of 'Print p'
which solves the problem when realizing that within a compound statement objects and variables may be defined. Inside a compound statement, a type name followed by a variable name is the grammatical form of a variable definition. Parentheses can be used to break priorities, but if there are no priorities to break, they have no effect, and are simply ignored by the compiler. In statement 3 the parentheses allowed us to get rid of the blank that's required between a type name and the variable name, but to the compiler we wrote
        Print (p);
which is, since the parentheses are superfluous, equal to
        Print p;
thus producing p's redeclaration.

As a further example: when we define a variable using a built-in type (e.g., double) using superfluous parentheses the compiler will quietly remove these parentheses for us:

    double ((((a))));       // weird, but OK.

To summarize our findings about anonymous variables:

7.6: The keyword `inline'

Let us take another look at the implementation of the function Person::name():
    std::string const &Person::name() const
    {
        return d_name;
    }
This function is used to retrieve the name field of an object of the class Person. Example:
    void showName(Person const &person)
    {
        cout << person.name();
    }
To insert person's name the following actions are performed: Especially the first part of these actions causes some time loss, since an extra function call is necessary to retrieve the value of the name field. Sometimes a faster procedure immediately making the d_name data member available is preferred without ever actually calling a function name. This can be realized using inline functions. An inline function is a request to the compiler to insert the function's code at the location of the function's call. This may speed up execution by avoiding a function call, which typically comes with some (stack handling and parameter passing) overhead. Note that inline is a request to the compiler: the compiler may decide to ignore it, and will probably ignore it when the function's body contains much code. Good programming discipline suggests to be aware of this, and to avoid inline unless the function's body is fairly small. More on this in section 7.6.2.

7.6.1: Defining members inline

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:
            std::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 is again added to the function's header.

Although members can be defined in-class (i.e., inside the class interface itself), it is considered bad practice for the following reasons:

Because of the above considerations inline members should not be defined in-class. Rather, they should be defined following the class interface. The Person::name member is therefore preferably defined as follows:
    class Person
    {
        public:
            std::string const &name() const;
    };

    inline std::string const &Person::name() const
    {
        return d_name;
    }

If it is ever necessary to cancel Person::name's inline implementation, then this becomes its non-inline implementation:

    #include "person.ih"

    std::string const &Person::name() const
    {
        return d_name;
    }
Only the inline keyword needs to be removed to obtain the correct non-inline implementation.

Defining members inline has the following effect: whenever an inline-defined function is called, the compiler may insert the function's body at the location of the function call. It may be that the function itself is never 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 using inline functions may result in multiple occurrences of the code of those functions in a program: 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 handles the use of inline functions as a request rather than a command. If the compiler considers the function too long, it will not grant the request. Instead it will treat the function as a normal function.

7.6.2: 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 at 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 found 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 always blurring the distinction between interface and implementation.

7.7: Local classes: classes inside functions

Classes are usually defined at the global or namespace level. However, it is entirely possible to define a local class, i.e., inside a function. Such classes are called local classes.

Local classes can be very useful in advanced applications involving inheritance or templates (cf. section 13.8). At this point in the C++ Annotations they have limited use, although their main features can be described. At the end of this section an example is provided.

#include <iostream>
#include <string>

using namespace std;

int main(int argc, char *argv[])
{
    static size_t staticValue = 0;

    class Local
    {
        int d_argc;             // non-static data members OK

        public:
            enum                // enums OK
            {
                VALUE = 5
            };
            Local(int argc)     // constructors and member functions OK
            :                   // in-class implementation required
                d_argc(argc)
            {
                                // global data: accessible
                cout << "Local constructor\n";
                                // static function variables: accessible
                staticValue += 5;
            }
            static void hello() // static member functions: OK
            {
                cout << "hello world\n";
            }
    };
    Local::hello();             // call Local static member
    Local loc(argc);            // define object of a local class.
}

7.8: The keyword `mutable'

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

C++ also allows the declaration of data members which may be modified, even by const member function. The declaration of such data members in the class interface start with the keyword mutable.

Mutable should be used for those data members that may be modified without logically changing the object, which might therefore still be considered a constant object.

An example of a situation where mutable is appropriately used is found in the implementation of a string class. Consider the std::string's c_str and data members. The actual data returned by the two members are identical, but c_str must ensure that the returned string is terminated by an ASCII-Z byte. As a string object has both a length and a capacity an easy way to implement c_str is to ensure that the string's capacity exceeds its length by at least one character. This invariant allows c_str to be implemented as follows:

    char const *string::c_str() const
    {
        d_data[d_length] = 0;
        return d_data;
    }
This implementation logically does not modify the object's data as the bytes beyond the object's initial (length) characters have undefined values. But in order to use this implementation d_data must be declared mutable:
    mutable char *d_data;

The keyword mutable is also 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 keyword mutable should sparingly be used. Data modified by const member functions should never logically modify the object, and it should be easy to demonstrate this. As a rule of thumb: do not use mutable unless there is a very clear reason (the object is logically not altered) for violating this rule.

7.9: Header file organization

In section 2.5.10 the requirements for header files when a C++ program also uses C functions were discussed. Header files containing class interfaces have additional requirements.

First, source files. With the exception of the occasional classless function, source files contain the code of member functions of classes. here 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 process many header files which aren't actually used by the function to compile.

With computers running faster and faster (and compilers getting smarter and smarter) I think the second alternative is to be preferred over the first alternative. So, as a starting point source files of a particular class MyClass could be 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.

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
Unfortunately 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 to this problem is to use a forward class reference before the class interface, and to include the corresponding class header file beyond 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 other classes are involved and with (non-inline) member functions having class-type return values or parameters.

This setup doesn't work with composition, nor with in-class 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
The class String can't declare a File object as a composed member: such a situation would again result 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's source files.

This approach allows us to introduce yet another refinement:

7.9.1: Using namespaces in header files

When entities from namespaces are used in header files, no using directive should be specified in those 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 wants 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\n";       // won'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::Inserter, then, because of the using directive in the user program, it considers cout a std::ostream. Consequently, the compiler reports an error.

As a rule of thumb, header files intended for general use should not contain using declarations. This rule does not hold true for header files which are only included 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.

7.10: Sizeof applied to class data members (C++0x)

In the C++0x standard the sizeof operator can be applied to data members of classes without the need to specify an object as well. Consider:
    class Data
    {
        std::string d_name;
        ...
    };
To obtain the size of Data's d_name member C++0x allows the following expression:
    sizeof(Data::d_name);
However, note that the compiler observes data protection here as well. Sizeof(Data::d_name) can only be used where d_name may be visible as well, i.e., by Data's member functions and friends.

7.11: Unrestricted Unions (C++0x, 4.6)

The C++0x standard allows unions to be defined consisting of objects for which a non-trivial constructor is defined. The example illustrates how such an unrestricted union may be defined. The data field u_string is an object of the class std::string for which non-trivial constructors are available:
    union Union
    {
        int u_int;
        double u_double;
        std::string u_string;
    };