- Next chapter
- Previous chapter
- Table of contents

# Chapter 3: A first impression of C++

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

In this chapter the usage of C++ is further explored. The possibility to declare functions in `struct`s is further illustrated using examples. The concept of a `class` is introduced.

## 3.1: More extensions of C in C++

Before we continue with the `real' object-oriented approach to programming, we first introduce some extensions to the C programming language, encountered in C++: not mere differences between C and C++, but syntactical constructs and keywords that are not found in C.

### 3.1.1: The scope resolution operator ::

The syntax of C++ introduces a number of new operators, of which the scope resolution operator `::` is described first. This operator can be used in situations where a global variable exists with the same name as a local variable:

        #include <stdio.h>

        int
            counter = 50;                   // global variable

        int main()
        {
            for (register int counter = 1;  // this refers to the
                 counter < 10;              // local variable
                 counter++)
            {
                printf("%d\n",
                        ::counter           // global variable
                        /                   // divided by
                        counter);           // local variable
            }
            return (0);
        }

In this code fragment the scope operator is used to address a global variable instead of the local variable with the same name. The usage of the scope operator is more extensive than just this, but the other purposes will be described later.

### 3.1.2: cout, cin and cerr

In analogy to C, C++ defines standard input- and output streams which are opened when a program is executed. The streams are:

- `cout`, analogous to `stdout`,

- `cin`, analogous to `stdin`,

- `cerr`, analogous to `stderr`.

Syntactically these streams are not used with functions: instead, data are read from the streams or written to them using the operators `<<`, called the insertion operator and `>>`, called the extraction operator. This is illustrated in the example below:

        #include <iostream>

        void main()
        {
            int
                ival;
            char
                sval[30];

            cout << "Enter a number:" << endl;
            cin >> ival;
            cout << "And now a string:" << endl;
            cin >> sval;

            cout << "The number is: " << ival << endl
                 << "And the string is: " << sval << endl;
        }

This program reads a number and a string from the `cin` stream (usually the keyboard) and prints these data to `cout`. Concerning the streams and their usage we remark the following:

- The streams are declared in the header file `iostream`.

- The streams `cout`, `cin` and `cerr` are in fact `objects' of a given class (more on classes later), processing the input and output of a program. Note that the term `object', as used here, means the set of data and functions which defines the item in question.

- The stream `cin` reads data and copies the information to variables (e.g., `ival` in the above example) using the extraction operator `>>`. We will describe later how operators in C++ can perform quite different actions than what they are defined to do by the language grammar, such as is the case here. We've seen function overloading. In C++ operators can also have multiple definitions, which is called operator overloading.

- The operators which manipulate `cin`, `cout` and `cerr` (i.e., `>>` and `<<`) also manipulate variables of different types. In the above example `cout << ival` results in the printing of an integer value, whereas `cout << "Enter a number"` results in the printing of a string. The actions of the operators therefore depend on the type of supplied variables.

- Special symbolic constants are used for special situations. The termination of a line written by `cout` is realized by inserting the `endl` symbol, rather than using the string `"\n"`.

The streams `cin`, `cout` and `cerr` are in fact not part of the C++ grammar, as defined in the compiler which parses source files. The streams are part of the definitions in the header file `iostream`. This is comparable to the fact that functions as `printf()` are not part of the C grammar, but were originally written by people who considered such functions handy and collected them in a run-time library.

Whether a program uses the old-style functions like `printf()` and `scanf()` or whether it employs the new-style streams is a matter of taste. Both styles can even be mixed. A number of advantages and disadvantages is given below:

- Compared to the standard `C` functions `printf()` and `scanf()`, the usage of the insertion and extraction operators is more `type-safe`. The format strings which are used with `printf()` and `scanf()` can define wrong format specifiers for their arguments, for which the compiler sometimes can't warn. In contrast, argument checking with `cin`, `cout` and `cerr` is performed by the compiler. Consequently it isn't possible to err by providing an `int` argument in places where, according to the format string, a string argument should appear.

- The functions `printf()` and `scanf()`, and other functions which use format strings, in fact implement a mini-language which is interpreted at run-time. In contrast, the `C++` compiler knows exactly `which` in- or output action to perform given which argument.

- The usage of the left-shift and right-shift operators in the context of the streams does illustrate the possibilities of `C++`. Again, it requires a little getting used to, coming from C, but after that these overloaded operators feel rather comfortably.

The iostream library has a lot more to offer than just `cin, cout` and `cerr`. In chapter 11 iostreams will be covered in greater detail.

### 3.1.3: The keyword const

The keyword `const` very often occurs in C++ programs, even though it is also part of the C grammar, where it's much less used.

This keyword is a modifier which states that the value of a variable or of an argument may not be modified. In the below example an attempt is made to change the value of a variable `ival`, which is not legal:

        int main()
        {
            int const               // a constant int..
                ival = 3;           // initialized to 3

            ival = 4;               // assignment leads
                                    // to an error message

            return (0);
        }

This example shows how `ival` may be initialized to a given value in its definition; attempts to change the value later (in an assignment) are not permitted.

Variables which are declared `const` can, in contrast to C, be used as the specification of the size of an array, as in the following example:

        int const
            size = 20;
        char
            buf[size];          // 20 chars big

A further usage of the keyword `const` is seen in the declaration of pointers, e.g., in pointer-arguments. In the declaration

        char const *buf;

`buf` is a pointer variable, which points to `char`s. Whatever is pointed to by `buf` may not be changed: the `char`s are declared as `const`. The pointer `buf` itself however may be changed. A statement as `*buf = 'a';` is therefore not allowed, while `buf++` is.

In the declaration

        char *const buf;

`buf` itself is a `const` pointer which may not be changed. Whatever `char`s are pointed to by `buf` may be changed at will.

Finally, the declaration

        char const *const buf;

is also possible; here, neither the pointer nor what it points to may be changed.

The rule of thumb for the placement of the keyword `const` is the following: whatever occurs just prior to the keyword may not be changed. The definition or declaration in which `const` is used should be read from the variable or function identifier back to the type indentifier:

> ``Buf is a const pointer to const characters''

This rule of thumb is especially handy in cases where confusion may occur. In examples of C++ code, one often encounters the reverse: `const` preceding what should not be altered. That this may result in sloppy code is indicated by our second example above:

        char const *buf;

What must remain constant here? According to the sloppy interpretation, the pointer cannot be altered (since `const` precedes the pointer-*). In fact, the charvalues are the constant entities here, as will be clear when it is tried to compile the following program:

        int main()
        {
            char const *buf = "hello";

            buf++;                  // accepted by the compiler
            *buf = 'u';             // rejected by the compiler

            return (0);
        }

Compilation fails on the statement `*buf = 'u';`, not on the statement `buf++`.

### 3.1.4: References

Besides the normal declaration of variables, C++ allows `references' to be declared as synonyms for variables. A reference to a variable is like an alias; the variable name and the reference name can both be used in statements which affect the variable:

        int
            int_value;
        int
            &ref = int_value;

In the above example a variable `int_value` is defined. Subsequently a reference `ref` is defined, which due to its initialization addresses the same memory location which `int_value` occupies. In the definition of `ref`, the reference operator `&` indicates that `ref` is not itself an integer but a reference to one. The two statements

        int_value++;            // alternative 1
        ref++;                  // alternative 2

have the same effect, as expected. At some memory location an `int` value is increased by one --- whether that location is called `int_value` or `ref` does not matter.

References serve an important function in C++ as a means to pass arguments which can be modified (`variable arguments' in Pascal-terms). E.g., in standard C, a function which increases the value of its argument by five but which returns nothing (`void`), needs a pointer argument:

        void increase(int *valp)        // expects a pointer
        {                               // to an int
            *valp += 5;
        }

        int main()
        {
            int
                x;

            increase(&x)                // the address of x is
            return (0);                 // passed as argument
        }

This construction can also be used in C++ but the same effect can be achieved using a reference:

        void increase(int &valr)            // expects a reference
        {                                   // to an int
            valr += 5;
        }

        int main()
        {
            int
                x;

            increase(x);                    // a reference to x is
            return (0);                     // passed as argument
        }

The way in which C++ compilers implement references is actually by using pointers: in other words, references in C++ are just ordinary pointers, as far as the compiler is concerned. However, the programmer does not need to know or to bother about levels of indirection. (Compare this to the Pascal way: an argument which is declared as `var` is in fact also a pointer, but the programmer needn't know.)

It can be argued whether code such as the above is clear: the statement `increase` `(x)` in the `main()` function suggests that not `x` itself but a copy is passed. Yet the value of `x` changes because of the way `increase()` is defined.

Our suggestions for the usage of references as arguments to functions are therefore the following:

- In those situations where a called function does not alter its arguments, a copy of the variable can be passed:

              void some_func(int val)
              {
                  printf("%d\n", val);
              }

              int main()
              {
                  int
                      x;

                  some_func(x);           // a copy is passed, so
                  return (0);             // x won't be changed
              }

- When a function changes the value of its argument, the address or a reference can be passed, whichever you prefer:

              void by_pointer(int *valp)
              {
                  *valp += 5;
              }

              void by_reference(int &valr)
              {
                  valr += 5;
              }

              int main ()
              {
                  int
                      x;

                  by_pointer(&x);             // a pointer is passed
                  by_reference(x);            // x is altered by reference
                  return (0);                 // x might be changed
              }

- References have an important role in those cases where the argument will not be changed by the function, but where it is desirable to pass a reference to the variable instead of a copy of the whole variable. Such a situation occurs when a large variable, e.g., a `struct`, is passed as argument, or is returned from the function. In these cases the copying operations tend to become significant factors when the entire structure must be copied, and it is preferred to use references. If the argument isn't changed by the function, or if the caller shouldn't change the returned information, the use of the `const` keyword is appropriate and should be used.

  Consider the following example:

          struct Person                       // some large structure
          {
              char
                  name [80],
                  address [90];
              double
                  salary;
          };

          Person
             person[50];                      // database of persons

          void printperson (Person const &p)  // printperson expects a
          {                                   // reference to a structure
              printf ("Name: %s\n"            // but won't change it
                      "Address: %s\n",
              p.name, p.address);
          }

          Person const &getperson(int index)  // get a person by indexvalue
          {
              ...
              return (person[index]);         // a reference is returned,
          }                                   // not a copy of person[index]

          int main ()
          {
              Person
                  boss;

              printperson (boss);             // no pointer is passed,
                                              // so variable won't be
                                              // altered by function
              printperson(getperson(5));      // references, not copies
                                              // are passed here
              return (0);
          }

- It should furthermore be noted here that there is another reason for using references when passing objects as function arguments: when passing a reference to an object, the activation of a copy constructor is avoided. We have to postpone this argument to chapter 5

References also can lead to extremely `ugly' code. A function can also return a reference to a variable, as in the following example:

        int &func()
        {
            static int
                value;

            return (value);
        }

This allows the following constructions:

        func() = 20;
        func() += func ();

It is probably superfluous to note that such constructions should not normally be used. Nonetheless, there are situations where it is useful to return a reference. Even though this is discussed later, we have seen an example of this phenomenon at our previous discussion of the iostreams. In a statement like `cout << "Hello" << endl;`, the insertion operator returns a reference to `cout`. So, in this statement first the `"Hello"` is inserted into `cout`, producing a reference to `cout`. Via this reference the `endl` is then inserted in the `cout` object, again producing a reference to `cout`. This latter reference is not further used.

A number of differences between pointers and references is pointed out in the list below:

- A reference cannot exist by itself, i.e., without something to refer to. A declaration of a reference like

  `int &ref;`

  is not allowed; what would `ref` refer to?

- References can, however, be declared as `external`. These references were initialized elsewhere.

- Reference may exist as parameters of functions: they are initialized when the function is called.

- References may be used in the return types of functions. In those cases the function determines to what the return value will refer.

- Reference may be used as data members of classes. We will return to this usage later.

- In contrast, pointers are variables by themselves. They point at something concrete or just ``at nothing''.

- References are aliases for other variables and cannot be re-aliased to another variable. Once a reference is defined, it refers to its particular variable.

- In contrast, pointers can be reassigned to point to different variables.

- When an address-of operator `&` is used with a reference, the expression yields the address of the variable to which the reference applies. In contrast, ordinary pointers are variables themselves, so the address of a pointer variable has nothing to do with the address of the variable pointed to.

## 3.2: Functions as part of structs

The first chapter described that functions can be part of `struct`s (see section 2.5.16). Such functions are called member functions or methods. This section discusses the actual definition of such functions.

The code fragment below illustrates a `struct` in which data fields for a name and address are present. A function `print()` is included in the `struct` definition:

        struct person
        {
            char
                name [80],
                address [80];
            void
                print (void);
        };

The member function `print()` is defined using the structure name (`person`) and the scope resolution operator (`::`):

        void person::print()
        {
            printf("Name:      %s\n"
                   "Address:   %s\n", name, address);
        }

In the definition of this member function, the function name is preceded by the `struct` name followed by `::`. The code of the function shows how the fields of the `struct` can be addressed without using the type name: in this example the function `print()` prints a variable `name`. Since `print()` is a part of the `struct` `person`, the variable `name` implicitly refers to the same type.

The usage of this `struct` could be, e.g.:

        person
            p;

        strcpy(p.name, "Karel");
        strcpy(p.address, "Rietveldlaan 37");
        p.print();

The advantage of member functions lies in the fact that the called function can automatically address the data fields of the structure for which it was invoked. As such, in the statement `p.print()` the structure `p` is the `substrate': the variables `name` and `address` which are used in the code of `print()` refer to the same `struct p`.

## 3.3: Several new data types

In C the following basic data types are available: `void, char, short, int, long, float` and `double`. C++ extends these five basic types with several extra types: the types `bool, wchar_t` and `long double`. The type `long double` is merely a double-long `double` datatype. Apart from these basic types a standard type `string` is available. The datatypes `bool`, `wchar_t` and `string` are covered in the following sections.

### 3.3.1: The `bool' data type

In C the following basic data types are available: `void, char, int, float` and `double`. C++ extends these five basic types with several extra types. In this section the type `bool` is introduced.

The type `bool` represents boolean (logical) values, for which the (now reserved) values `true` and `false` may be used. Apart from these reserved values, integral values may also be assigned to variables of type `bool`, which are implicitly converted to `true` and `false` according to the following conversion rules (assume `intValue` is an `int`-variable, and `boolValue` is a `bool`-variable):

            // from int to bool:
        boolValue = intValue ? true : false;

            // from bool to int:

        intValue = boolValue ? 1 : 0;

Furthermore, when `bool` values are inserted into, e.g., `cout`, then `1` is written for `true` values, and `0` is written for `false` values. Consider the following example:

        cout << "A true value: "  << true << endl
             << "A false value: " << false << endl;

The `bool` data type is found in other programming languages as well. Pascal has its type `Boolean`, and Java has a `boolean` type. Different from these languages, C++'s type `bool` acts like a kind of `int` type: it's primarily a documentation-improving type, having just two values `true` and `false`. Actually, these values can be interpreted as `enum` values for `1` and `0`. Doing so would neglect the philosophy behind the `bool` data type, but nevertheless: assigning `true` to an `int` variable neither produces warnings nor errors.

Using the `bool`-type is generally more intuitively clear than using `int`. Consider the following prototypes:

            bool exists(char const *fileName);  // (1)
            int  exists(char const *fileName);  // (2)

For the first prototype `(1)`, most people will expect the function to return `true` if the given filename is the name of an existing file. However, using the second prototype some ambiguity arises: intuitively the returnvalue 1 is appealing, as it leads to constructions like

            if (exists("myfile"))
                cout << "myfile exists";

On the other hand, many functions (like `access(), stat(),` etc.) return `0` to indicate a successful operation, reserving other values to indicate various types of errors.

As a rule of thumb we suggest the following: If a function should inform its caller about the success or failure of its task, let the function return a `bool` value. If the function should return success or various types of errors, let the function return enum values, documenting the situation when the function returns. Only when the function returns a meaningful integral value (like the sum of two `int` values), let the function return an `int` value.

### 3.3.2: The `wchar_t' data type

The `wchar_t` type is an extension of the `char` basic type, to accomodate wide character values, such as the Unicode character set. `Sizeof(wchar_t)` is 2, allowing for 65,536 different character values.

Note that a programming language like Java has a data type `char` that is comparable to C++'s `wchar_t` type, while Java's `byte` data type is comparable to C++'s `char` type. Very convenient....

### 3.3.3: The `string' data type

C++ offers a large number of facilities to implement solutions for common problems. Most of these facilities are part of the Standard Template Library or they are implemented as generic algorithms (see chapter 10).

Among the facilities C++ programmers have developed over and over again (as reflected in the Annotations) are those for manipulating chunks of text, commonly called strings. The C programming language offers rudimentary string support: the ascii-z terminated series of characters is the foundation on which a large amount of code has been built.

Standard C++ now offers a `string` type of its own. In order to use `string`-type objects, the header file `string` must be included in sources.

Actually, `string` objects are class type variables, and the `class` is introduced for the first time in chapter 4. However, in order to use a string, it is not necessary to know what a class is. In this section the operators that are available for strings and some other operations are discussed. The operations that can be performed on strings take the form

`stringVariable.operation(argumentList)`

For example, if `string1` and `string2` are variables of type `string`, then

`string1.compare(string2)`

can be used to compare both strings. A function like `compare()`, which is part of the `string`-class is called a memberfunction. The `string` class offers a large number of these memberfunctions, as well as extensions of some well-known operators, like the assignment (`=`) and the comparison operator (`==`). These operators and functions are discussed in the following sections.

3.3.3.1: Operations on strings

Some of the operations that can be performed on strings return indices within the strings. Whenever such an operation fails to find an appropriate index, the value `string::npos` is returned. This value is a (symbolic) value of type `string::size_type`, which is (for all practical purposes) an `int`.

Note that in all operations where `string` objects can be used as arguments, `char const *` values and variables can be used as well.

Some `string`-memberfunctions use iterators. Iterators will be covered in section 10.1. The memberfunctions that use iterators are listed in the next section (3.3.3.2), they are not further illustrated below.

The following operations can be performed on strings:

- String objects can be initialized. For the initialization a plain `ascii-z` string, another `string` object, or an implicit initialization can be used. In the example, note that the implicit initialization does not have an argument, and does not use the function argumentlist notation.

          #include <string>

          int main()
          {
              string
                  stringOne("Hello World"),   // using plain ascii-Z
                  stringTwo(stringOne),       // using another string object
                  stringThree;                // implicit initialization to ""
                                              // do not use: stringThree();
              return (0);
          }

- String objects can be assigned to each other. For this the assignment operator (i.e., the `=` operator) can be used, which accepts both a `string` object and a C-style characterstring as its right-hand argument:

          #include <string>

          int main()
          {
              string
                  stringOne("Hello World"),
                  stringTwo;

              stringTwo = stringOne;      // assign stringOne to stringTwo
              stringTwo = "Hello world";  // assign a C-string to StringTwo

              return (0);
          }

- In the previous example a standard C-string (an ascii-Z string) was implicitly converted to a `string`-object. The reverse conversion (converting a `string` object to a standard C-string) is not performed automatically. In order to obtain the `C`-string that is stored within the `string` object itself, the memberfunction `c_str()`, which returns a `char const *`, can be used:

          #include <iostream>
          #include <string>

          int main()
          {
              string
                  stringOne("Hello World");
              char const
                  *Cstring = stringOne.c_str();

              cout << Cstring << endl;

              return (0);
          }

- The individual elements of a string object can be reached for reading or writing. For this operation the subscript-operator (`[]`) is available, but not the pointer dereferencing operator (`*`). The subscript operator does not perform range-checking. If range-checking is required, the `at()` memberfunction can be used instead of the subscript-operator:

          #include <string>

          int main()
          {
              string
                  stringOne("Hello World");

              stringOne[6] = 'w';         // now "Hello world"
              if (stringOne[0] == 'H')
                  stringOne[0] = 'h';     // now "hello world"

              // THIS WON'T COMPILE:
              //  *stringOne = 'H';

              // Now using the at() memberfunction:

              stringOne.at(6) =
                      stringOne.at(0);    // now "Hello Horld"
              if (stringOne.at(0) == 'H')
                  stringOne.at(0) = 'W';  // now "Wello Horld"

              return (0);
          }

  When an illegal index is passed to the `at()` memberfunction, the program aborts.

- Two strings can be compared for (in)equality or ordering, using the `==, !=, <, <=, >` and `>=` operators or the `compare()` memberfunction can be used. The `compare()` memberfunction comes in different flavors, the plain one (having another `string` object as argument) offers a bit more information than the operators do. The returnvalue of the `compare()` memberfunction may be used for lexicographical ordering: a negative value is returned if the string stored in the string object using the `compare()` memberfunction (in the example: `stringOne`) is located earlier in the alphabet (based on the standard ascii-characterset) than the string stored in the string object passed as argument to the `compare()` memberfunction.

          #include <iostream>
          #include <string>

          int main()
          {
              string
                  stringOne("Hello World"),
                  stringTwo;

              if (stringOne != stringTwo)
                  stringTwo = stringOne;

              if (stringOne == stringTwo)
                  stringTwo = "Something else";

              if (stringOne.compare(stringTwo) > 0)
                  cout << "stringOne after stringTwo in the alphabet\n";
              else if (stringOne.compare(stringTwo) < 0)
                  cout << "stringOne before stringTwo in the alphabet\n";
              else
                  cout << "Both strings are the same";

              // Alternatively:

              if (stringOne > stringTwo)
                  cout << "stringOne after stringTwo in the alphabet\n";
              else if (stringOne < stringTwo)
                  cout << "stringOne before stringTwo in the alphabet\n";
              else
                  cout << "Both strings are the same";

              return (0);
          }

  There is no memberfunction to perform a case insensitive comparison of strings.

  Overloaded forms of the `compare()` memberfunction have one or two extra arguments.

  - If the `compare()` memberfunction is used with two arguments, then the second argument is an index position in the current `string`-object. It indicates the index position in the current `string` object where the comparison should start.
  - If the `compare()` memberfunction is used with three arguments, then the third argument indicates the number of characters that should be compared.
  See the following example for further details about the `compare()` function.

          #include <iostream>
          #include <string>

          int main()
          {
              string
                  stringOne("Hello World");

              // comparing from a certain offset in stringOne

              if (!stringOne.compare("ello World", 1))
                  cout << "comparing 'Hello world' from index 1"
                          " to 'ello World': ok\n";

              // comparing from a certain offset in stringOne over a certain
              // number of characters in "World and more"

              if (!stringOne.compare("World and more", 6, 5))
                  cout << "comparing 'Hello World' from index 6 over 5 positions"
                          " to 'World and more': ok\n";

              // The same, but this fails, as all of the chars in stringOne
              // starting at index 6 are compared, not just 3 chars.
              // number of characters in "World and more"

              if (!stringOne.compare("World and more", 6, 3))
                  cout << "comparing 'Hello World' from index 6 over 3 positions"
                          " to 'World and more': ok\n";
              else
                  cout << "Unequal (sub)strings\n";

              return (0);
          }

- A `string` can be appended to another string. For this the `+=` operator can be used, as well as the `append()` memberfunction. Like the `compare()` function, the `append()` memberfunction may have two extra arguments. The first argument is the string to be appended, the second argument specifies the index position of the first character that will be appended. The third argument specifies the number of characters that will be appended. If the first argument is of type `char const *`, only a second argument may be specified. In that case, the second argument specifies the number of characters of the first argument that are appended to the `string` object. Furthermore, the `+` operator can be used to append two strings within an expression:

          #include <iostream>
          #include <string>

          int main()
          {
              string
                  stringOne("Hello"),
                  stringTwo("World");

              stringOne += " " + stringTwo;

              stringOne = "hello";
              stringOne.append(" world");

              // append only 5 characters:
              stringOne.append(" ok. >This is not used<", 5);

              cout << stringOne << endl;

              string
                  stringThree("Hello");

              // append " World":
              stringThree.append(stringOne, 5, 6);

              cout << stringThree << endl;

              return (0);
          }

  The `+` operator can be used in cases where at least one term of the `+` operator is a `string` object (the other term can be a `string, char const *` or `char`).

  When neither operand of the `+` operator is a `string`, at least one operand must be converted to a `string` object first. An easy way to do this is to use an anonymous string object:

  `string("hello") + " world";`

- So, the `append()` memberfunction is used to append characters at the end of a `string`. It is also possible to insert characters somewhere within a `string`. For this the memberfunction `insert()` is available.

  The `insert()` memberfunction to insert (parts of) a `string` has at least two, and at most four arguments:

  - The first argument is the offset in the current `string` object where another string should be inserted.
  - The second argument is the string to be inserted.
  - The third argument specifies the index position of the first character in the provided `string`-argument that will be inserted.
  - The fourth argument specifies the number of characters that will be inserted.
  If the first argument is of type `char const *`, the fourth argument is not available. In that case, the third argument indicates the number of characters of the provided `char const *` value that will be inserted.

          #include <iostream>
          #include <string>

          int main()
          {
              string
                  stringOne("Hell ok.");

              stringOne.insert(4, "o ");   // Insert "o " at position 4

              string
                  world("The World of C++");

                                          // insert "World" into stringOne
              stringOne.insert(6, world, 4, 5);

              cout << "Guess what ? It is: " << stringOne << endl;

              return (0);
          }

  Several other variants of `insert()` are available. See section 3.3.3.2 for details.

- At times, the contents of `string` objects must be replaced by other information. To replace parts of the contents of a `string` object by another string the memberfunction `replace()` can be used.

  The memberfunction has at least three and possibly five arguments, having the following meanings (see section 3.3.3.2 for overloaded versions of `replace()`, using different types of arguments):

  - The first argument indicates the position of the first character that must be replaced
  - The second argument gives the number of characters that must be replaced.
  - The third argument defines the replacement text (a `string` or `char const *`).
  - The fourth argument specifies the index position of the first character in the provided `string`-argument that will be inserted.
  - The fifth argument can be used to specify the number of characters that will be inserted.
  If the third argument is of type `char const *`, the fifth argument is not available. In that case, the fourth argument indicates the number of characters of the provided `char const *` value that will be inserted.

  The following example shows a very simple filechanger: it reads lines from `cin`, and replaces occurrences of a `searchstring' by a `replacestring'. Simple tests for the correct number of arguments and the contents of the provided strings (they should be unequal) are implemented using the `assert()` macro.

          #include <iostream>
          #include <string>
          #include <cassert>

          int main(int argc, char **argv)
          {
              assert(argc == 3 &&
                  "Usage: <searchstring> <replacestring> to process stdin");

              string
                  line,
                  search(argv[1]),
                  replace(argv[2]);

              assert(search != replace);

              while (getline(cin, line))
              {
                  while (true)
                  {
                      string::size_type
                          idx;

                      idx = line.find(search);

                      if (idx == string::npos)
                          break;

                      line.replace(idx, search.size(), replace);
                  }
                  cout << line << endl;
              }
              return (0);
          }

- A particular form of replacement is swapping: the memberfunction `swap()` swaps the contents of two `string`-objects. For example:

          #include <iostream>
          #include <string>

          int main()
          {
              string
                  stringOne("Hello"),
                  stringTwo("World");

              cout << "Before: stringOne: " << stringOne << ", stringTwo: "
                  << stringTwo << endl;

              stringOne.swap(stringTwo);

              cout << "After: stringOne: " << stringOne << ", stringTwo: "
                  << stringTwo << endl;
              return (0);
          }

- Another form of replacement is to remove characters from the string. For this the memberfunction `erase()` is available. The standard form has two optional arguments:
  - If no arguments are specified, the stored string is erased completely: it becomes the empty string (`string()` or `string("")`).
  - The first argument may be used to specify the offset of the first character that must be erased.
  - The second argument may be used to specify the number of characters that are to be erased.
  See section 3.3.3.2 for overloaded versions of `erase()`. An example of the use of `erase()` is given below:

          #include <string>

          int main()
          {
              string
                  stringOne("Hello Cruel World");

              stringOne.erase(5, 6);

              cout << stringOne << endl;

              stringOne.erase();

              cout << "'" << stringOne << "'\n";

              return (0);
          }

- To find substrings in a `string` the memberfunction `find()` can be used. This function looks for the string that is provided as its first argument in the `string` object calling `find()` and returns the index of the first character of the substring if found. If the string is not found `string::npos` is returned. The memberfunction `rfind()` looks for the substring from the end of the `string` object back to its beginning. An example using `find()` was given earlier.

- To extract a substring from a `string` object, the memberfunction `substr()` is available. The returned `string` object contains a copy of the substring in the `string`-object calling `substr()` The memberfunction has two optional arguments:
  - Without arguments, a copy of the `string` itself is returned.
  - The first argument may be used to specify the offset of the first character to be returned.
  - The second argument may be used to specify the number of characters that are to be returned.
  For example:

          #include <string>

          int main()
          {
              string
                  stringOne("Hello World");

              cout << stringOne.substr(0, 5)  << endl
                   << stringOne.substr(6)     << endl
                   << stringOne.substr()      << endl;

              return (0);
          }

- Whereas `find()` is used to find a substring, the functions `find_first_of(), find_first_not_of(), find_last_of()` and `find_last_not_of()` can be used to find sets of characters (Unfortunately, regular expressions are not supported here). The following program reads a line of text from the standard input stream, and displays the substrings starting at the first vowel, starting at the last vowel, and not starting at the first digit:

          #include <string>

          int main()
          {
              string
                  line;

              getline(cin, line);

              string::size_type
                  pos;

              cout << "Line: " << line << endl
                  << "Starting at the first vowel:\n"
                  << "'"
                      << (
                          (pos = line.find_first_of("aeiouAEIOU")) != string::npos ?
                              line.substr(pos)
                          :
                              "*** not found ***"
                          ) << "'\n"
                  << "Starting at the last vowel:\n"
                  << "'"
                      << (
                          (pos = line.find_last_of("aeiouAEIOU")) != string::npos ?
                              line.substr(pos)
                          :
                              "*** not found ***"
                          ) << "'\n"
                  << "Not starting at the first digit:\n"
                  << "'"
                      << (
                          (pos = line.find_first_not_of("1234567890"))
                                                                  != string::npos ?
                              line.substr(pos)
                          :
                              "*** not found ***"
                          ) << "'\n";
              return (0);
          }

- The number of characters that are stored in a string are obtained by the `size()` memberfunction, which, like the standard C function `strlen()` does not include the terminating ascii-Z character. For example:

          #include <iostream>
          #include <string>

          int main()
          {
              string
                  stringOne("Hello World");

              cout << "The length of the stringOne string is "
                  << stringOne.size() << " characters\n";

              return (0);
          }

- If the size of a string is not enough (or if it is too large), the memberfunction `resize()` can be used to make it longer or shorter. Note that operators like `+` automatically resize the `string` when needed.

- The `size()` memberfunction can be used to determine whether a string holds no characters as well. Alternatively, the `empty()` memberfunction can be used:

          #include <iostream>
          #include <string>

          int main()
          {
              string
                  stringOne;

              cout << "The length of the stringOne string is "
                  << stringOne.size() << " characters\n"
                      "It is " << (stringOne.empty() ? "" : " not ")
                  << "empty\n";

              stringOne = "";

              cout << "After assigning a \"\"-string to a string-object\n"
                      "it is " << (stringOne.empty() ? "also" : " not")
                  << " empty\n";

              return (0);
          }

- The `istream &getline(istream instream, string target, char delimiter)` memberfunction may be used to read a line of text (up to the first delimiter or the end of the stream) from `instream`.

  The delimiter has a default value `'\n'`. It is removed from `instream`, but it is not stored in `target`. The function `getline()` was used in several earlier examples (e.g., with the replace() memberfunction).

3.3.3.2: Overview of operations on strings

In this section the available operations on strings are summarized. There are four subparts here: the `string`-initializers, the `string`-iterators, the `string`-operators and the `string`-memberfunctions.

The memberfunctions are ordered alphabetically by the name of the operation. Below, `object` is a `string`-object, and `argument` is either a `string` or a `char const *`, unless overloaded versions tailored to `string` and `char const *` parameters are explicitly mentioned. `Object` is used in cases where a `string` object is initialized or given a new value. `Argument` remains unchanged. Sometimes multiple arguments are required, in which case `argument1, argument2` etc. are used.

With memberfunctions the types of the parameters are given in a function-prototypical way. With several memberfunctions iterators are used. At this point in the Annotations it's a bit premature to discuss iterators, but for referential purposes they have to be mentioned nevertheless. So, a forward reference is used here: see section 10.1 for a more detailed discussion of iterators.

Finally, note that all `string`-memberfunctions returning indices in `object` return the predefined constant `string::pos` if no suitable index could be found.

- The string-initializers:
- The `string`-iterators:
- The `string`-operators:
- The string memberfunctions:

- `char &object.at(string::size_type pos)`: The character (reference) at the indicated position is returned (it may be reassigned). The memberfunction performs range-checking, aborting the program if an invalid index is passed.
- `string &object.append(InputIterator begin, InputIterator end)`: Using this memberfunction the range of characters implied by the `begin` and `end InputIterators` are appended to `object`.
- `string &object.append(string argument, string::size_type pos = 0; string::size_type n = string::npos)`:
  - If only `argument` is given, it is appended to `object`.
  - If `pos` is specified as well, `argument` is appended from index position `pos` until the end of `argument`.
  - If all three arguments are provided, `n` characters of `argument`, starting at index position `pos` are appended to `object`.
  If `argument` is of type `char const *`, parameter `pos` is not available. So, with `char const *` arguments, either all characters or an initial subset of the characters of the provided `char const *` argument are appended to `object`.
  - `string &object.append(string::size_type n, char c)`: Using this memberfunction, `n` characters `c` can be appended to `object`.
- `string &object.assign(string argument, string::size_type pos = 0; string::size_type n = string::npos)`:
  - If only `argument` is given, it is assigned to `object`.
  - If `pos` is specified as well, `object` is assigned from index position `pos` until the end of `argument`.
  - If all three arguments are provided, `n` characters of `argument`, starting at index position `pos` are assigned to `object`.
  If `argument` is of type `char const *`, no parameter `pos` is available. So, with `char const *` arguments, either all characters or an initial subset of the characters of the provided `char const *` argument are assigned to `object`.
  - `string &object.assign(string::size_type n, char c)`: Using this memberfunction, `n` characters `c` can be assigned to `object`.
- `string::size_type argument.capacity()`: returns the number of characters that can currently be stored inside `argument`.
- `int argument1.compare(string argument2, string::size_type pos, string::size_type n)`: This memberfunction may be used to compare (according to the ascii-character set) the strings stored in `argument1` and `argument2`. The parameter `n` may be used to specify the number of characters in `argument2` that are used in the comparison, the parameter `pos` may be used to specify the initial character in `argument1` that is used in the comparison.
- `char const *argument.c_str`: the memberfunction returns the contents of `argument` as an `ascii-Z` C-string.
- `char const *argument.data()`: returns the raw text stored in `argument`.
- `bool argument.empty()`: returns `true` if `argument` contains no data.
- `string &object.erase(string::size_type pos; string::size_type n)`. This memberfunction can be used to erase (a sub)string of `object`. The basic form erases `object` completely. The working of other forms of `erase()` depend on the specification of extra arguments:
  - If `pos` is specified, the contents of `object` are erased from index position `pos` until the end of `object`.
  - If `pos` and `n` are provided, `n` characters of `object`, starting at index position `pos` are erased.
- `iterator object.erase(iterator p)`: The contents of `object` are erased until (iterator) position `p`. The iterator `p` is returned.
- `iterator object.erase(iterator f, iterator l)`: The range of characters of `object`, implied by the `iterators f` and `l` are erased. The iterator `f` is returned.
- `string::string::size_type argument1.find(string argument2, string::size_type pos)`: This memberfunction returns the index in `argument1` where `argument2` is found. If `pos` is omitted, the search starts at the beginning of `argument1`. If `pos` is provided, it refers to the index in `argument1` where the search for `argument2` should start.
- `string::size_type argument1.find(char const *argument2, string::size_type pos, string::size_type n)`: This memberfunction returns the index in `argument1` where `argument2` is found. The parameter `n` indicates the number of characters of `argument2` that should be used in the search: it defines a partial string starting at the beginning of `argument2`. If omitted, all characters in `argument2` are used. The parameter `pos` refers to the index in `argument1` where the search for `argument2` should start. If the parameter `pos` is omitted as well, `argument1` is scanned completely.
- `string::size_type argument.find(char c, string::size_type pos)`: This memberfunction returns the index in `argument` where `c` is found. If the argument `pos` is omitted, the search starts at the beginning of `argument`. If provided, it refers to the index in `argument` where the search for `argument` should start.
- `string::size_type argument1.find_first_of(string argument2, string::size_type pos)`: This memberfunction returns the index in `argument1` where any character in `argument2` is found. If the argument `pos` is omitted, the search starts at the beginning of `argument1`. If provided, it refers to the index in `argument1` where the search for `argument2` should start.
- `string::size_type argument1.find_first_of(char const* argument2, string::size_type pos, string::size_type n)`: This memberfunction returns the index in `argument1` where a character of `argument2` is found, no matter which character. The parameter `n` indicates the number of characters of `argument1` that should be used in the search: it defines a partial string starting at the beginning of `argument1`. If omitted, all characters in `argument1` are used. The parameter `pos` refers to the index in `argument1` where the search for `argument2` should start. If the parameter `pos` is omitted as well, `argument1` is scanned completely.
- `string::size_type argument.find_first_of(char c, string::size_type pos)`: This memberfunction returns the index in `argument1` where character `c` is found. If the argument `pos` is omitted, the search starts at the beginning of `argument1`. If provided, it refers to the index in `argument1` where the search for `argument` should start.
- `string::size_type argument1.find_first_not_of(string argument2, string::size_type pos)`: This memberfunction returns the index in `argument1` where a character not appearing in `argument2` is found. If the argument `pos` is omitted, the search starts at the beginning of `argument1`. If provided, it refers to the index in `argument1` where the search for `argument2` should start.
- `string::size_type argument1.find_first_not_of(char const* argument2, string::size_type pos, string::size_type n)`: This memberfunction returns the index in `argument1` where any character not appearing in `argument2` is found. The parameter `n` indicates the number of characters of `argument1` that should be used in the search: it defines a partial string starting at the beginning of `argument1`. If omitted, all characters in `argument1` are used. The parameter `pos` refers to the index in `argument1` where the search for `argument2` should start. If the parameter `pos` is omitted as well, `argument1` is scanned completely.
- `string::size_type argument.find_first_not_of(char c, string::size_type pos)`: This memberfunction returns the index in `argument` where another character than `c` is found. If the argument `pos` is omitted, the search starts at the beginning of `argument`. If provided, it refers to the index in `argument` where the search for `c` should start.
- `string::size_type argument1.find_last_of(string argument2, string::size_type pos)`: This memberfunction returns the last index in `argument1` where a character in `argument2` is found. If the argument `pos` is omitted, the search starts at the beginning of `argument1`. If provided, it refers to the index in `argument1` where the search for `argument2` should start.
- `string::size_type argument1.find_last_of(char const* argument2, string::size_type pos, string::size_type n)`: This memberfunction returns the last index in `argument1` where a character of `argument2` is found. The parameter `n` indicates the number of characters of `argument1` that should be used in the search: it defines a partial string starting at the beginning of `argument1`. If omitted, all characters in `argument1` are used. The parameter `pos` refers to the index in `argument1` where the search for `argument2` should start. If the parameter `pos` is omitted as well, `argument1` is scanned completely.
- `string::size_type argument.find_last_of(char c, string::size_type pos)`: This memberfunction returns the last index in `argument` where character `c` is found. If the argument `pos` is omitted, the search starts at the beginning of `argument`. If provided, it refers to the index in `argument` where the search for `c` should start.
- `string::size_type argument1.find_last_not_of(string argument2, string::size_type pos)`: This memberfunction returns the last index in `argument1` where any character not appearing in `argument2` is found. If the argument `pos` is omitted, the search starts at the beginning of `argument1`. If provided, it refers to the index in `argument1` where the search for `argument2` should start.
- `string::size_type argument1.find_last_not_of(char const* argument2, string::size_type pos, string::size_type n)`: This memberfunction returns the last index in `argument1` where any character not appearing in `argument2` is found. The parameter `n` indicates the number of characters of `argument1` that should be used in the search: it defines a partial string starting at the beginning of `argument1`. If omitted, all characters in `argument1` are used. The parameter `pos` refers to the index in `argument1` where the search for `argument2` should start. If the parameter `pos` is omitted as well, all of `argument1` is scanned.
- `string::size_type argument.find_last_not_of(char c, string::size_type pos)`: This memberfunction returns the last index in `argument` where another character than `c` is found. If the argument `pos` is omitted, the search starts at the beginning of `argument`. If provided, it refers to the index in `argument` where the search for `c` should start.
- `istream &getline(istream instream, string object, char delimiter)`. This memberfunction can be used to read a line of text (up to the first delimiter or the end of the stream) from `instream`. The delimiter has a default value `'\n'`. It is removed from `instream`, but it is not stored in `object`.
- `string &object.insert(string::size_type t_pos, string argument, string::size_type pos; string::size_type n)`. This memberfunction can be used to insert (a sub)string of `argument` into `object`, at `object`'s index position `t_pos`. The basic form inserts `argument` completely at index `t_pos`. The way other forms of `insert()` work depend on the specification of extra arguments:
  - If `pos` is specified, `argument` is inserted from index position `pos` until the end of `argument`.
  - If `pos` and `n` are provided, `n` characters of `argument`, starting at index position `pos` are inserted into `object`.
  If `argument` is of type `char const *`, no parameter `pos` is available. So, with `char const *` arguments, either all characters or an initial subset of the characters of the provided `char const *` argument are inserted into `object`.
  - `string &object.insert(string::size_type t_pos, string::size_type n, char c)`: Using this memberfunction, `n` characters `c` can be inserted to `object`.
- `iterator object.insert(iterator p, char c)`: The character `c` is inserted at the (iterator) position `p` in `object`. The iterator `p` is returned.
- `iterator object.insert(iterator p, string::size_type n, char c)`: `N` characters `c` are inserted at the (iterator) position `p` in `object`. The iterator `p` is returned.
- `iterator object.insert(iterator p, InputIterator first, InputIterator last)`: The range of characters implied by the `InputIterators first` and `last` are inserted at the (iterator) position `p` in `object`. The iterator `p` is returned.
- `string::size_type argument.length()`: returns the number of characters stored in `argument`.
- `string::size_type argument.max_size()`: returns the maximum number of characters that can be stored in `argument`.
- `string& object.replace(string::size_type pos1, string::size_type n1, const string argument, string::size_type pos2, string::size_type n2)`: The substring of `n1` characters of `object`, starting at position `pos1` is replaced by `argument`. If `n1` is set to 0, the memberfunction inserts `argument` into `object`.
  The basic form uses `argument` completely. The way other forms of `replace()` work depends on the specification of extra arguments:
  - If `pos2` is specified, `argument` is inserted from index position `pos2` until the end of `argument`.
  - If `pos2` and `n2` are provided, `n2` characters of `argument`, starting at index position `pos2` are inserted into `object`.
  If `argument` is of type `char const *`, no parameter `pos2` is available. So, with `char const *` arguments, either all characters or an initial subset of the characters of the provided `char const *` argument are replaced in `object`.
- `string &object.replace(string::size_type pos, string::size_type n1, string::size_type n2, char c)`: This memberfunction can be used to replace `n1` characters of `object`, starting at index position `pos`, by `n2 c`-characters. The argument `n2` may be omitted, in which case the string to be replaced is replaced by just one character `c`.
- `string& object.replace (iterator i1, iterator i2, string argument)`: Here, the string implied by the iterators `i1` and `i2` are replaced by the string `str`. If `argument` is a `char const *`, an extra argument `n` may be used, specifying the number of characters of `argument` that are used in the replacement.
- `iterator object.replace(iterator f, iterator l, string argument)`: The range of characters of `object`, implied by the `iterators f` and `l` are replaced by `argument`. If `argument` is a `char const *`, an extra argument `n` may be used, specifying the number of characters of `argument` that are used in the replacement. The string `object` is returned.
- `iterator object.replace(iterator f, iterator l, string::size_type n, char c)`: The range of characters of `object`, implied by the `iterators f` and `l` are replaced by `n c`-characters. The iterator `f` is returned.
- `string object.replace(iterator i1, iterator i2, InputIterator j1, InputIterator j2)`: here the range of characters implied by the iterators `i1` and `i2` is replaced by the range of characters implied by the `InputIterators j1` and `j2`.
- `void object.resize(string::size_type n, char c)`: The string stored in `object` is resized to `n` characters. The second argument is optional. If provided and the string is enlarged, the extra characters are initialized to `c`.
- `string::size_type argument1.rfind(string argument2, string::size_type pos)`: This memberfunction returns the index in `argument1` where `argument2` is found. Searching proceeds from the end of `argument1` back to the beginning. If the argument2 `pos` is omitted, the search starts at the beginning of `argument1`. If provided, it refers to the index in `argument1` where the search for `argument2` should start.
- `string::size_type argument1.rfind(char const *argument2, string::size_type pos, string::size_type n)`: This memberfunction returns the index in `argument1` where `argument2` is found. Searching proceeds from the end of `argument1` back to the beginning. The parameter `n` indicates the number of characters of `argument2` that should be used in the search: it defines a partial string starting at the beginning of `argument2`. If omitted, all characters in `argument2` are used. The parameter `pos` refers to the index in `argument1` where the search for `argument2` should start. If the parameter `pos` is omitted as well, all of `argument1` is scanned.
- `string::size_type argument1.rfind(char c, string::size_type pos)`: This memberfunction returns the index in `argument1` where `c` is found. Searching proceeds from the end of `argument1` back to the beginning. If the argument2 `pos` is omitted, the search starts at the beginning of `argument1`. If provided, it refers to the index in `argument1` where the search for `argument2` should start.
- `string::size_type argument.size()`: returns the number of characters stored in `argument`.
- `string argument.substr(string::size_type pos, string::size_type n)`: This memberfunction returns a substring of `argument`. The parameter `n` may be used to specify the number of characters of `argument` that are returned. The parameter `pos` may be used to specify the index of the first character of `argument` that is returned. Either `n` or both arguments may be omitted.
- `string::size_type object1.swap(string object2)`: swaps the contents of the `object1` and `object2`. In this case, `object2` cannot be a `char const *`.

- `object = argument`. Assignment of `argument` to `object`. May also be used for initializing `string` objects.
- `object = c`. Assignment of `char c` to `object`. May not be used for initializing `string` objects.
- `object += argument`. Appends `argument` to `object`. `Argument` may also be a `char` value.
- `argument1 + argument2`. Within expressions, `strings` may be added. The right-hand term may be a `string` object, a `char const *` value or a `char` value. Note that the left-hand operand must be a `string` object. So, in the following example the first expression will compile correctly, but the second expression won't compile:

          void fun()
          {
              char const
                  *asciiz = "hello";
              string
                  first = "first",
                  second;

              second = first + asciiz;    // compiles ok
              second = asciiz + first;    // won't compile
          }

- `object[string::size_type pos]`. The subscript-operator may be used to assign individual characters of `object` or to retrieve these characters. There is no range-checking. If range checking is required, use the `at()` memberfunction, summarized earlier.
- `argument1 == argument2`. The equality operator may be used to compare a `string` object to another `string` or `char const *` value. The operator `!=` is available as well. The returnvalue is a `bool`, which is `true` if the two strings are equal (i.e., contain the same characters). `!=` returns `false` in that case.
- `argument1 < argument2`. The less-than operator may be used to compare the ordering within the Ascii-character set of `argument1` and `argument2`. The operators `<=, >` and `>=` are available as well.
- `ostream stream; stream << argument`. The insertion-operator may be used with `string` objects.
- `istream stream; stream >> object`. The extraction-operator may be used with `string` objects. It operates analogously to the extraction of characters into a character array, but `object` is automatically resized to the required number of characters.

See section 10.1 for details about iterators.

- Forward iterators:
  - `begin()`
  - `end()`
- Reverse iterators:
  - `rbegin()`
  - `rend()`

- `string object`: Initializes `object` to an empty string.
- `string object(string::size_type n, char c)`: Initializes `object` with `n` characters `c`.
- `string object(string argument)`: Initializes `object` with `argument`.
- `string object(string argument, string::size_type idx, string::size_type n = pos)`: Initializes `object` with `argument`, using `n` characters of `argument`, starting at index `idx`.
- `string object(InputIterator begin, InputIterator end)`: Initializes `object` with the range of characters implied by the provided `InputIterators`.

## 3.4: Data hiding: public, private and class

As mentioned previously (see section 2.3), C++ contains special syntactical possibilities to implement data hiding. Data hiding is the ability of one program part to hide its data from other parts; thus avoiding improper addressing or name collisions of data.

C++ has two special keywords which are concerned with data hiding: `private` and `public`. These keywords can be inserted in the definition of a `struct`. The keyword `public` defines all subsequent fields of a structure as accessible by all code; the keyword `private` defines all subsequent fields as only accessible by the code which is part of the `struct` (i.e., only accessible for the member functions) (Besides `public` and `private`, C++ defines the keyword `protected`. This keyword is not often used and it is left for the reader to explore.). In a `struct` all fields are `public`, unless explicitly stated otherwise.

With this knowledge we can expand the `struct` `person`:

        struct person
        {
            public:
                void
                    setname (char const *n),
                    setaddress (char const *a),
                    print (void);
                char const
                    *getname (void),
                    *getaddress (void);
            private:
                char
                    name [80],
                    address [80];
        };

The data fields `name` and `address` are only accessible for the member functions which are defined in the `struct`: these are the functions `setname()`, `setaddress()` etc.. This property of the data type is given by the fact that the fields `name` and `address` are preceded by the keyword `private`. As an illustration consider the following code fragment:

        person
            x;

        x.setname ("Frank");        // ok, setname() is public
        strcpy (x.name, "Knarf");   // error, name is private

The concept of data hiding is realized here in the following manner. The actual data of a `struct` `person` are named only in the structure definition. The data are accessed by the outside world by special functions, which are also part of the definition. These member functions control all traffic between the data fields and other parts of the program and are therefore also called `interface' functions. The data hiding which is thus realized is illustrated further in figure 2.

figure 2: Private data and public interface functions of the class Person.

Also note that the functions `setname()` and `setaddress()` are declared as having a `char const *` argument. This means that the functions will not alter the strings which are supplied as their arguments. In the same vein, the functions `getname()` and `getaddress()` return a `char const *`: the caller may not modify the strings which are pointed to by the return values.

Two examples of member functions of the `struct` `person` are shown below:

        void person::setname(char const *n)
        {
            strncpy(name, n, 79);
            name[79] = '\0';
        }

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

In general, the power of the member functions and of the concept of data hiding lies in the fact that the interface functions can perform special tasks, e.g., checks for the validity of data. In the above example `setname()` copies only up to 79 characters from its argument to the data member `name`, thereby avoiding array boundary overflow.

Another example of the concept of data hiding is the following. As an alternative to member functions which keep their data in memory (as do the above code examples), a runtime library could be developed with interface functions which store their data on file. The conversion of a program which stores `person` structures in memory to one that stores the data on disk would mean the relinking of the program with a different library.

Though data hiding can be realized with `structs`, more often (almost always) classes are used instead. A `class` is in principle equivalent to a `struct` except that unless specified otherwise, all members (data or functions) are `private`. As far as `private` and `public` are concerned, a `class` is therefore the opposite of a `struct`. The definition of a `class` `person` would therefore look exactly as shown above, except for the fact that instead of the keyword `struct`, `class` would be used. Our typographic suggestion for class names is a capital as first character, followed by the remainder of the name in lower case (e.g., `Person`).

## 3.5: Structs in C vs. structs in C++

At the end of this chapter we would like to illustrate the analogy between C and C++ as far as `struct`s are concerned. In C it is common to define several functions to process a `struct`, which then require a pointer to the `struct` as one of their arguments. A fragment of an imaginary C header file is given below:

        // definition of a struct PERSON_
        typedef struct
        {
            char
                name[80],
                address[80];
        } PERSON_;

        // some functions to manipulate PERSON_ structs

        // initialize fields with a name and address
        extern void initialize(PERSON_ *p, char const *nm,
                               char const *adr);

        // print information
        extern void print(PERSON_ const *p);

        // etc..

In C++, the declarations of the involved functions are placed inside the definition of the `struct` or `class`. The argument which denotes which `struct` is involved is no longer needed.

        class Person
        {
            public:
                void initialize(char const *nm, char const *adr);
                void print(void);
                // etc..
            private:
                char
                    name[80],
                    address[80];
        };

The `struct` argument is implicit in C++. A function call in C like

        PERSON_
            x;

        initialize(&x, "some name", "some address");

becomes in C++:

        Person
            x;

        x.initialize("some name", "some address");

## 3.6: Namespaces

Imagine a math teacher who wants to develop an interactive math program. For this program functions like `cos(), sin(), tan()` etc. are to be used accepting arguments in degrees rather than arguments in radials. Unfortunately, the functionname `cos()` is already in use, and that function accepts radials as its arguments, rather than degrees.

Problems like these are normally solved by looking for another name, e.g., the functionname `cosDegrees()` is defined. C++ offers an alternative solution by allowing namespaces to be defined: areas or regions in the code in which identifiers are defined which cannot conflict with existing names defined elsewhere.

### 3.6.1: Defining namespaces

Namespaces are defined according to the following syntax:

        namespace identifier
        {
            // declared or defined entities
            // (declarative region)
        }

The identifier used in the definition of a namespace is a standard C++ identifier.

Within the declarative region, introduced in the above code example, functions, variables, structs, classes and even (nested) namespaces can be defined or declared. Namespaces cannot be defined within a block. So it is not possible to define a namespace within, e.g., a function. However, it is possible to define a namespace using multiple namespace declarations. Namespaces are said to be open. This means that a namespace `CppAnnotations` could be defined in a file `file1.cc` and also in a file `file2.cc`. The entities defined in the `CppAnnotations` namespace of files `file1.cc` and `file2.cc` are then united in one `CppAnnotations` namespace region. For example:

        // in file1.cc
        namespace CppAnnotations
        {
            double cos(double argInDegrees)
            {
                ...
            }
        }

        // in file2.cc
        namespace CppAnnotations
        {
            double sin(double argInDegrees)
            {
                ...
            }
        }

Both `sin()` and `cos()` are now defined in the same `CppAnnotations` namespace.

Namespace entities can also be defined outside of their namespaces. This topic is discussed in section 3.6.4.1.

3.6.1.1: Declaring entities in namespaces

Instead of defiing entities in a namespace, entities may also be declared in a namespace. This allows us to put all the declarations of a namespace in a header file which can thereupon be included in sources in which the entities of a namespace are used. Such a header file could contain, e.g.,

        namespace CppAnnotations
        {
            double cos(double degrees);
            double sin(double degrees);
        }

3.6.1.2: A closed namespace

Namespaces can be defined without a name. Such a namespace is anonymous and it restricts the usability of the defined entities to the source file in which the anonymous namespace is defined.

The entities that are defined in the anonymous namespace are accessible the same way as `static` functions and variables in C. The `static` keyword can still be used in C++, but its use is more dominant in `class` definitions (see chapter 4). In situations where static variables or functions are necessary, the use of the anonymous namespace is preferred.

### 3.6.2: Referring to entities

Given a namespace and entities that are defined or declared in it, the scope resolution operator can be used to refer to the entities that are defined in the namespace. For example, to use the function `cos()` defined in the `CppAnnotations` namespace the following code could be used:

        // assume the CppAnnotations namespace is declared in the next header
        // file:
        #include <CppAnnotations>

        int main()
        {
            cout << "The cosine of 60 degrees is: " <<
                    CppAnnotations::cos(60) << endl;
            return (0);
        }

This is a rather cumbersome way to refer to the `cos()` function in the `CppAnnotations` namespace, especially so if the function is frequently used.

Therefore, an abbreviated form (just `cos()` can be used by declaring that `cos()` will refer to `CppAnnotations::cos()`. For this, the `using`-declaration can be used. Following

        using CppAnnotations::cos;      // note: no function prototype, just the
                                        // name of the entity is required.

the function `cos()` will refer to the `cos()` function in the `CppAnnotations` namespace. This implies that the standard `cos()` function, accepting radials, cannot be used automatically anymore. The plain scope resolution operator can be used to reach the generic `cos()` function:

        int main()
        {
            using CppAnnotations::cos;
            ...
            cout << cos(60)         // this uses CppAnnotations::cos()
                << ::cos(1.5)       // this uses the standard cos() function
                << endl;
            return (0);
        }

Note that a `using`-declaration can be used inside a block. The `using` declaration prevents the definition of entities having the same name as the one used in the `using` declaration: it is not possible to use a using declaration for a variable `value` in the `CppAnnotations` namespace, and to define (or declare) an identically named object in the block in which the `using` declaration was placed:

        int main()
        {
            using CppAnnotations::value;
            ...
            cout << value << endl;  // this uses CppAnnotations::value

            int
                value;              // error: value already defined.

            return (0);
        }

3.6.2.1: The using directive

A generalized alternative to the `using`-declaration is the `using`-directive:

        using namespace CppAnnotations;

Following this directive, all entities defined in the `CppAnnotations` namespace are uses as if they where declared by `using` declarations.

While the `using`-directive is a quick way to import all the names of the `CppAnnotations` namespace (assuming the entities are declared or defined separately from the directive), it is at the same time a somewhat dirty way to do so, as it is less clear which entity will be used in a particular block of code.

If, e.g., `cos()` is defined in the `CppAnnotations` namespace, the function `CppAnnotations::cos()` will be used when `cos()` is called in the code. However, if `cos()` is not defined in the `CppAnnotations` namespace, the standard `cos()` function will be used. The `using` directive does not document as clearly which entity will be used as the `using` declaration does. For this reason, the `using` directive is somewhat deprecated.

### 3.6.3: The standard namespace

Apart from the anonymous namespace, many entities of the runtime available software (e.g., `cout, cin, cerr` and the templates defined in the Standard Template Library, see chapter 10) are now defined in the `std` namespace.

Regarding the discussion in the previous section, one should use a `using` declaration for these entities. For example, in order to use the `cout` stream, the code should start with something like

        #include <iostream>

        using std::cout;

Often, however, the identifiers that are defined in the `std` namespace can all be accepted without much thought. Because of that, one often encounters a `using` directive, rather than a `using` declaration with the `std` namespace. So, instead of the mentioned `using declaration` a construction like

        #include <iostream>

        using namespace std;

is often encountered. Whether this should be encouraged is subject of some dispute. Long `using` declarations are of course inconvenient too. So as a rule of thumb one might decide to stick to `using` declarations, up to the point where the list becomes impractically long, at which point a `using` directive could be considered.

### 3.6.4: Nesting namespaces and namespace aliasing

Namespaces can be nested. The following code shows the definition of a nested namespace:

        namespace CppAnnotations
        {
            namespace Virtual
            {
                void
                    *pointer;
            }
        }

Now the variable `pointer` defined in the `Virtual` namespace, nested under the `CppAnnotations` namespace. In order to refer to this variable, the following options are available:

- The fully qualified name can be used. A fully qualified name of an entity is a list of all the namespaces that are visited until the definition of the entity is reached, glued together by the scope resolution operator:

          int main()
          {
              CppAnnotations::Virtual::pointer = 0;
              return (0);
          }

- A `using` declaration for `CppAnnotations::Virtual` can be used. Now `Virtual` can be used without any prefix, but `pointer` must be used with the `Virtual::` prefix:

          ...
          using CppAnnotations::Virtual;

          int main()
          {
              Virtual::pointer = 0;
              return (0);
          }

- A `using` declaration for `CppAnnotations::Virtual::pointer` can be used. Now `pointer` can be used without any prefix:

          ...
          using CppAnnotations::Virtual::pointer;

          int main()
          {
              pointer = 0;
              return (0);
          }

- A `using` directive or directives can be used:

          ...
          using namespace CppAnnotations::Virtual;

          int main()
          {
              pointer = 0;
              return (0);
          }

  Alternatively, two separate `using` directives could have been used:

          ...
          using namespace CppAnnotations;
          using namespace Virtual;

          int main()
          {
              pointer = 0;
              return (0);
          }

- A combination of `using` declarations and `using` directives can be used. E.g., a `using` directive can be used for the `CppAnnotations` namespace, and a `using` declaration can be used for the `Virtual::pointer` variable:

          ...
          using namespace CppAnnotations;
          using Virtual::pointer;

          int main()
          {
              pointer = 0;
              return (0);
          }

At every `using` directive all entities of that namespace can be used without any further prefix. If a namespace is nested, then that namespace can also be used without any further prefix. However, the entities defined in the nested namespace still need the nested namespace's name. Only by using a `using` declaration or directive the qualified name of the nested namespace can be omitted.

When fully qualified names are somehow preferred, while the long form (like `CppAnnotations::Virtual::pointer`) is at the same time considered too long, a namespace alias can be used:

        namespace CV = CppAnnotations::Virtual;

This defines `CV` as an alias for the full name. So, to refer to the `pointer` variable the construction

        CV::pointer = 0;

Of course, a namespace alias itself can also be used in a `using` declaration or directive.

3.6.4.1: Defining entities outside of their namespaces

It is not strictly necessary to define members of namespaces within a `namespace` region. By prefixing the member by its namespace or namespaces a member can be defined outside of a namespace region. This may be done at the global level, or at intermediate levels in the case of nested namespaces. So while it is not possible to define a member of namespace `A` within the region of namespace `C`, it is possible to define a member of namespace `A::B` within the region of namespace `A`.

Note, however, that when a member of a namespace is defined outside of a namespace region, it must still be declared within the region.

Assume the type `int INT8[8]` is defined in the `CppAnnotations::Virtual` namespace.

Now suppose we want to define (at the global level) a member function `funny` of namespace `CppAnnotations::Virtual`, returning a pointer to `CppAnnotations::Virtual::INT8`. The definition of such a function could be as follows (first everything is defined inside the `CppAnnotations::Virtual` namespace):

        namespace CppAnnotations
        {
            namespace Virtual
            {
                void
                    *pointer;

                typedef int INT8[8];

                INT8 *funny()
                {
                    INT8
                        *ip = new INT8[1];

                    for (int idx = 0; idx < sizeof(INT8) / sizeof(int); ++idx)
                        (*ip)[idx] = (1 + idx) * (1 + idx);

                    return (ip);
                }
            }
        }

The function `funny()` defines an array of one `INT8` vector, and returns its address after initializing the vector by the squares of the first eight natural numbers.

Now the function `funny()` can be defined outside of the `CppAnnotations::Virtual` as follows:

        namespace CppAnnotations
        {
            namespace Virtual
            {
                void
                    *pointer;

                typedef int INT8[8];

                INT8 *funny();
            }
        }

        CppAnnotations::Virtual::INT8 *CppAnnotations::Virtual::funny()
        {
            INT8
                *ip = new INT8[1];

            for (int idx = 0; idx < sizeof(INT8) / sizeof(int); ++idx)
            {
                cout << idx << endl;
                (*ip)[idx] = idx * idx;
            }

            return (ip);
        }

At the final code fragment note the following:

- `funny()` is declared inside of the `CppAnnotations::Virtual` namespace.
- `` The definition outside of the namespace region requires us to use the fully qualified name of the function and of its returntype.
- `` Inside the block of the function `funny` we are within the `CppAnnotations::Virtual` namespace, so inside the function fully qualified names (e.g., for `INT8` are not required any more.

Finally, note that the function could also have been defined in the `CppAnnotations` region. It that case the `Virtual` namespace would have been required for the function name and its returntype, while the internals of the function would remain the same:

        namespace CppAnnotations
        {
            namespace Virtual
            {
                void
                    *pointer;

                typedef int INT8[8];

                INT8 *funny();
            }

            Virtual::INT8 *Virtual::funny()
            {
                INT8
                    *ip = new INT8[1];

                for (int idx = 0; idx < sizeof(INT8) / sizeof(int); ++idx)
                {
                    cout << idx << endl;
                    (*ip)[idx] = idx * idx;
                }

                return (ip);
            }
        }

- Next chapter
- Previous chapter
- Table of contents