There are only three lines in this program that deal with the string class:

#include <string>

This includes the string class' library header.


Waaaaaayyyy down in the draw_line_segment() function, we find:

    const string line(length, symbol);

This declares a string constant line and initializes it to contain length copies of the drawing symbol. How does *that* work?! Well, let's review memory location declarations for a second:

Just like built-in types, string variable/constant memory locations can be declared in these ways:

    string x;          // declare a variable x of type string; it will
                       // initially contain an empty string

    string y = "Hi";   // declare a variable y of type string; it will
                       // initially contain the value "Hi"

    string z("Hello"); // declare a variable z of type string; it will
                       // initially contain the value "Hello"

    string w = z;      // declare a variable of type string; it will
                       // initially contain the same value as z (may be
                       // a variable or a constant)

    string v(y);       // declare a variable of type string; it will
                       // initially contain the same value as y (may be
                       // a variable or a constant)

    string u = '!' + v; // declare a variable of type string; it will
                        // initially contain the value resulting from
                        // concatenating v's current value to the end of
                        // the character '!' (v may be either a variable
                        // or a constant)

    string t(u+", ");  // declare a variable of type string; it will
                       // initially contain the value resulting from
                       // concatenating the current value of u with the
                       // string literal ", " (u may be either a variable
                       // or a constant)

    const string b = "Hi";   // declare a constant b of type string; it will
                             // always contain the value "Hi"

    const string c("Hello"); // declare a constant c of type string; it will
                             // always contain the value "Hello"

    const string d = c;     // declare a constant of type string; it will
                            // always contain the same value as c (must
                            // be a constant)

    const string e(b);      // declare a constant of type string; it will
                            // always contain the same value as b (must
                            // be a constant)

    const string f = '!' + e; // declare a constant of type string; it will
                              // always contain the value resulting from
                              // concatenating e's current value to the
                              // character '!' (e, as here, must be a constant)

    const string g(f+", ");  // declare a constant of type string; it will
                             // always contain the value resulting from
                             // concatenating the current value of f to the
                             // string literal ", " (f, as here, must be a
                             // constant)

All of these variants are demonstrated in the initialization.C example (see).

Note the slight difference for the variable x. In the short case, the memory location contains garbage bit values. In the string case, the memory location contains an empty string. This is an improvement that class objects have over the built-in types -- they initialize themselves even when the programmer using them fails to specify initialization.

classes are so smart at initializing objects of their type, in fact, that they provide other mechanisms for memory location initialization. Above we saw three methods of initialization for class memory locations: default, initialization/parameterized, and copy.

When we declared x as a string variable, it was 'default' initialized. This form of initialization happens when the programmer fails/forgets to initialize the variable/constant (although it really isn't as useful for constants; *grin*).

In declaring w, v, d, e, f, g, u, and t we used the 'copy' form of initialization. This form happens when the programmer asks that one memory location be initialized with a copy of the contents of a previously existing object of the same type. (Here, w is a copy of z, v is a copy of y, d is a copy of c, and e is a copy of b. f, g, u, and t are all copies of the results of various 'calculations'.)

The remaining declarations all use the 'initialization' or 'parameterized' form of initialization. In this form, the programmer asks that the memory location be filled in as they specify. All of these examples use initialization from a (related) literal type. But, that isn't the only initialization/parameterized pattern available for string class objects. There are two other forms available: from literal string and count; from count and character.

The first of these, from literal string and count, will initialize the string class object with the first 'count' characters from the string literal. This form won't be of much use to us this semester, but should be kept in mind for those going on to later.

The second, from count and character, will initialize the string class object with 'count' copies of the specified character. This is the form being used in the figure drawing program! Again:

    const string line(length, symbol);

line is to be a constant object of type string which is formed of 'length' copies of the drawing symbol. This form of initialization proves useful surprisingly often.


The next statement prints this line:

    cout << line; //string(length,'*'); //string(length, symbol);

And gives a couple of alternatives to how we could have printed it. (Of course, the literal '*' would only work correctly if that was what the user had specified. *grin*)

The thing to note here is that we are initializing objects that we don't name! Neither 'string(length,'*')' nor 'string(length, symbol)' have names given to them. These are anonymous objects similar to those temporary objects which result from calculations (like the subtraction, multiplication, and concatenations above). But, here we are explicitly requesting that the compiler create these objects in context. With calculation results, the compiler implicitly creates the objects because it needs a place to store the results.

Such anonymous objects shouldn't be overused, but can be handy when you don't need to keep the object/value around for continuing calculations or actions.