CONTENTS

Appendix J. ANSWERS TO REVIEW QUESTIONS

Chapter 2

1:

What are the modules of C++ programs called?

A:

They are called functions.

2:

What does the following preprocessor directive do?

#include <iostream>
A:

It causes the contents of the iostream file to be substituted for this directive before final compilation.

3:

What does the following statement do?

using namespace std;
A:

It makes definitions made in the std namespace available to a program.

4:

What statement would you use to print the phrase "Hello, world" and then start a new line?

A:
cout << "Hello, world\n";

or

cout << "Hello, world" << endl;
5:

What statement would you use to create an integer variable with the name cheeses?

A:
int cheeses;
6:

What statement would you use to assign the value 32 to the variable cheeses?

A:
cheeses = 32;
7:

What statement would you use to read a value from keyboard input into the variable cheeses?

A:
cin >> cheeses;
8:

What statement would you use to print "We have X varieties of cheese," where the current value of the cheeses variable replaces X?

A:
cout << "We have " << cheeses << " varieties of cheese\n";
9:

What does the following function header tell you about the function?

A:

It tells us that the function froop() expects to be called with one argument, which will be type double, and that the function will return a type int value.

10:

When do you not have to use the keyword return when you define a function?

A:

You don't have to use return in a function when the function has return type void. However, you can use it providing you don't give a return value:

return;

Chapter 3

1:

Why does C++ have more than one integer type?

A:

Having more than one integer type lets you choose the type best suited to a particular need. For example, you could use short to conserve space, long to guarantee storage capacity, or find that a particular type speeds up a particular calculation.

2:

Define the following:

  1. A short integer with the value 80

  2. An unsigned int integer with the value 42110

  3. An integer with the value 3000000000

A:
short rbis = 80;            // or short int rbis = 80;
unsigned int q = 42110;     // or unsigned q = 42110;
unsigned long ants = 3000000000;

Note

graphics/common.gif

Don't count on int being large enough to hold 3000000000.

3:

What safeguards does C++ provide to keep you from exceeding the limits of an integer type?

A:

C++ provides no automatic safeguards to keep you from exceeding integer limits; you can use the climits header file to determine what the limits are.

4:

What is the distinction between 33L and 33?

A:

The constant 33L is type long, whereas the constant 33 is type int.

5:

Consider the two C++ statements that follow. Are they equivalent?

char grade = 65;
char grade = 'A';
A:

The two statements are not really equivalent, although they have the same effect on some systems. Most important, the first statement assigns the letter A to grade only on a system using the ASCII code, while the second statement also works for other codes. Second, 65 is a type int constant, while 'A' is a type char constant.

6:

How could you use C++ to find out which character the code 88 represents? Come up with at least two ways.

A:

Here are four ways:

char c = 88;
cout << c << "\n";          // char type prints as character
cout.put(char(88));         // put() prints char as character
cout << char(88) << "\n";    // new-style type cast value to char
cout << (char)88 << "\n";    // old-style type cast value to char
7:

Assigning a long value to a float can result in a round-off error. What about assigning long to double?

A:

The answer depends on how large the two types are. If long is 4 bytes, there is no loss. That's because the largest long value would be about 2 billion, which is 10 digits. Because double provides at least 13 significant figures, no rounding would be needed.

8:

Evaluate the following expressions as C++ would:

  1. 8 * 9 + 2

  2. 6 * 3 / 4

  3. 3 / 4 * 6

  4. 6.0 * 3 / 4

  5. 15 % 4

A:
  1. 8 * 9 + 2 is 72 + 2 is 74

  2. 6 * 3 / 4 is 18 / 4 is 4

  3. 3 / 4 * 6 is 0 * 6 is 0

  4. 6.0 * 3 / 4 is 18.0 / 4 is 4.5

  5. 15 % 4 is 3

9:

Suppose x1 and x2 are two type double variables that you want to add as integers and assign to an integer variable. Construct a C++ statement for doing so.

A:

Either of the following work:

int pos = (int) x1 + (int) x2;
int pos = int(x1) + int(x2);

Chapter 4

1:

How would you declare each of the following?

  1. actors is an array of 30 char.

  2. betsie is an array of 100 short.

  3. chuck is an array of 13 float.

  4. dipsea is an array of 64 long double.

A:
  1. char actors[30];

  2. short betsie[100];

  3. float chuck[13];

  4. long double dipsea[64];

2:

Declare an array of five ints and initialize it to the first five odd positive integers.

A:
int oddly[5] = {1, 3, 5, 7, 9};
3:

Write a statement that assigns the sum of the first and last elements of the array in question 2 to the variable even.

A:
int even = oddly[0] + oddly[4];
4:

Write a statement that displays the value of the second element in the float array ideas.

A:
cout << ideas[1] << "\n"; // or << endl;
5:

Declare an array of char and initialize it to the string "cheeseburger".

A:
char lunch[13] = "cheeseburger"; // number of characters + 1

or

char lunch[] = "cheeseburger";  // let the compiler count elements
6:

Devise a structure declaration that describes a fish. The structure should include the kind, the weight in whole ounces, and the length in fractional inches.

A:
struct fish {
    char kind[20];
    int weight;
    float length;
};
7:

Declare a variable of the type defined in question 6 and initialize it.

A:
fish petes =
{
    "trout",
    13,
    12.25
};
8:

Use enum to define a type called Response with the possible values of Yes, No, and Maybe. Yes should be 1, No should be 0, and Maybe should be 2.

A:
enum Response {No, Yes, Maybe};
9:

Suppose ted is a double variable. Declare a pointer that points to ted and use the pointer to display ted's value.

A:
double * pd = &ted;
cout << *pd << "\n";
10:

Suppose treacle is an array of 10 floats. Declare a pointer that points to the first element of treacle and use the pointer to display the first and last elements of the array.

A:
float * pf = treacle;   // or = &treacle[0]
cout << pf[0] << " " << pf[9] << "\n";
            // or use *pf and *(pf + 9)
11:

Write a code fragment that asks the user to enter a positive integer and then creates a dynamic array of that many ints.

A:
unsigned int size;
cout << "Enter a positive integer: ";
cin >> size;
int * dyn = new int [size];
12:

Is the following valid code? If so, what does it print?

A:

Yes, it is valid. The expression "Home of the jolly bytes" is a string constant, hence it evaluates as the address of the beginning of the string. The cout object interprets the address of a char as an invitation to print a string, but the type cast (int *) converts the address to type pointer-to-int, which is then printed as an address. In short, the statement prints the address of the string.

13:

Write a code fragment that dynamically allocates a structure of the type described in question 6 and then reads a value for the kind member of the structure.

A:
struct fish
{
    char kind[20];
    int weight;
    float length;
};
fish * pole = new fish;
cout << "Enter kind of fish: ";
cin >> pole->kind;
14:

Listing 4.6 illustrates a problem with the following numeric input with line-oriented string input. How would replacing

cin.getline(address,80);

with

cin >> address;

affect the working of this program?

A:

Using cin >> address causes a program to skip over whitespace until it finds nonwhitespace. It then reads characters until it encounters whitespace again. Thus, it will skip over the newline following the numeric input, avoiding that problem. On the other hand, it will read just a single word, not an entire line.

Chapter 5

1:

What's the difference between an entry-condition loop and an exit-condition loop? Which kind is each of the C++ loops?

A:

An entry-condition loop evaluates a test expression before entering the body of the loop. If the condition initially is false, the loop never executes its body. An exit-condition loop evaluates a test expression after processing the body of the loop. Thus, the loop body is executed once even if the test expression initially is false. The for and while loops are entry-condition loops, and the do while loop is an exit-condition loop.

2:

What would the following code fragment print if it were part of a valid program?

int i;
for (i = 0; i < 5; i++)
      cout << i;
      cout << "\n";
A:

It would print the following:

01234

Note that the cout << "\n"; is not part of the loop body (no braces).

3:

What would the following code fragment print if it were part of a valid program?

int j;
for (j = 0; j < 11; j += 3)
      cout << j;
cout << "\n" << j << "\n";
A:

It would print the following:

0369
12
4:

What would the following code fragment print if it were part of a valid program?

int j = 5;
while ( ++j < 9)
      cout << j++ << "\n";
A:

It would print the following:

6
8
5:

What would the following code fragment print if it were part of a valid program?

int k = 8;
do
      cout <<" k = " << k << "\n";
while (k++ < 5);
A:

It would print the following:

k = 8
6:

Write a for loop that prints the values 1 2 4 8 16 32 64 by increasing the value of a counting variable by a factor of 2 each cycle.

A:

It's simplest to use the *= operator:

for (int num = 1; num <= 64; num *= 2)
    cout << num << " ";
7:

How do you make a loop body include more than one statement?

A:

You enclose the statements within paired braces to form a single compound statement, or block.

8:

Is the following statement valid? If not, why not? If so, what does it do?

int x = (1,024);

What about the following?

int y;
y = 1,024;
A:

Yes, the first statement is valid. The expression 1,024 consists of two expressions? and 024梛oined by a comma operator. The value is the value of the right-hand expression. This is 024, which is octal for 20, so the declaration assigns the value 20 to x. The second statement also is valid. However, operator precedence causes it to be evaluated as follows:

(y = 1), 024;

That is, the left expression sets y to 1, and the value of the entire expression, which isn't used, is 024, or 20.

9:

How does cin>>ch differ from cin.get(ch) and ch=cin.get() in how it views input?

A:

The cin >> ch form skips over spaces, newlines, and tabs when it encounters them. The other two forms read these characters.

Chapter 6

1:

Consider the following two code fragments for counting spaces and newlines:

// Version 1
while (cin.get(ch))    // quit on eof
{
      if (ch == ' ')
             spaces++;
      if (ch == '\n')
            newlines++;
}
// Version 2
while (cin.get(ch))    // quit on eof
{
      if (ch == ' ')
            spaces++;
      else if (ch == '\n')
            newlines++;
}

What advantages, if any, does the second form have over the first?

A:

Both versions give the same answers, but the if else version is more efficient. Consider what happens, for example, when ch is a space. Version 1, after incrementing spaces, tests to see whether the character is a newline. This wastes time because the program already has established that ch is a space and hence could not be a newline. Version 2, in the same situation, skips the newline test.

2:

In Listing 6.2, what is the effect of replacing ++ch with ch+1?

A:

Both ++ch and ch + 1 have the same numerical value. But ++ch is type char and prints as a character, while ch + 1, because it adds a char to an int, is type int and prints as a number.

3:

Consider carefully the following program:

#include <iostream>
using namespace std;
int main()
{
    char ch;
    int ct1, ct2;
    ct1 = ct2 = 0;
    while ((ch = cin.get()) != '$')
    {
        cout << ch;
        ct1++;
        if (ch = '$')
            ct2++;
        cout << ch;
    }
    cout <<"ct1 = " << ct1 << ", ct2 = " << ct2 << "\n";
    return 0;
}

Suppose we provide the following input, where graphics/ccc.gif represents pressing Enter:

Hi!
Send $10 or $20 now!

What is the output? (Recall that input is buffered.)

A:

Because the program uses ch = '$' instead of ch == '$', the combined input and output looks like this:

Hi!
H$i$!$
$Send $10 or $20 now!
S$e$n$d$ $ct1 = 9, ct2 = 9

Each character is converted to the $ character before being printed the second time. Also, the value of the expression ch = $ is the code for the $ character, hence nonzero, hence true; so ct2 is incremented each time.

4:

Construct logical expressions to represent the following conditions:

  1. weight is greater than or equal to 115 but less than 125.

  2. ch is q or Q.

  3. x is even but is not 26.

  4. x is even but is not a multiple of 26.

  5. donation is in the range 1000?000 or guest is 1.

  6. ch is a lowercase letter or an uppercase letter (assume the lowercase letters are coded sequentially and that the uppercase letters are coded sequentially but that there is a gap in the code between uppercase and lowercase).

A:
  1. weight >= 115 && weight < 125

  2. ch == 'q' || ch == 'Q'

  3. x % 2 == 0 && x != 26

  4. x % 2 == 0 && !(x % 26 == 0)

  5. donation >= 1000 && donation <= 2000 || guest == 1

  6. (ch >= 'a' && ch <= 'z') ||(ch >= 'A' && ch <= 'Z')

5:

In English the statement "I will not not speak" means the same as "I will speak." In C++, is !!x the same as x?

A:

Not necessarily. For example, if x is 10, then !x is 0 and !!x is 1. However, if x is a bool variable, then !!x is x.

6:

Construct a conditional expression that is equal to the absolute value of a variable. That is, if a variable x is positive, the value of the expression is just x, but if x is negative, the value of the expression is -x, which is positive.

A:
(x < 0)? -x : x

or

(x >= 0)? x : -x;
7:

Rewrite the following fragment using switch:

if (ch == 'A')
    a_grade++;
else if (ch == 'B')
    b_grade++;
else if (ch == 'C')
    c_grade++;
else if (ch == 'D')
    d_grade++;
else
    f_grade++;
A:
switch (ch)
{
    case 'A': a_grade++;
              break;
    case 'B': b_grade++;
              break;
    case 'C': c_grade++;
              break;
    case 'D': d_grade++;
              break;
    default:  f_grade++;
              break;
}
8:

In Listing 6.10, what advantage would there be in using character labels, such as a and c, instead of numbers for the menu choices and switch cases? (Hint: Think about what happens if the user types q in either case and what happens if the user types 5 in either case.)

A:

If you use integer labels and the user types a noninteger such as q, the program hangs up because integer input can't process a character. But if you use character labels and the user types an integer such as 5, character input will process 5 as a character. Then the default part of the switch can suggest entering another character.

9:

Consider the following code fragment:

int line = 0;
char ch;
while (cin.get(ch))
{
    if (ch == 'Q')
           break;
    if (ch != '\n')
           continue;
    line++;
}

Rewrite this code without using break or continue.

A:

Here is one version:

int line = 0;
char ch;
while (cin.get(ch) && ch != 'Q')
{
    if (ch == '\n')
        line++;
}

Chapter 7

1:

What are the three steps in using a function?

A:

The three steps are defining the function, providing a prototype, and calling the function.

2:

Construct function prototypes that match the following descriptions:

  1. igor() takes no arguments and has no return value.

  2. tofu() takes an int argument and returns a float.

  3. mpg() takes two type double arguments and returns a double.

  4. summation() takes the name of a long array and an array size as values and returns a long value.

  5. doctor() takes a string argument (the string is not to be modified) and returns a double value.

  6. ofcourse() takes a boss structure as an argument and returns nothing.

  7. plot() takes a pointer to a map structure as an argument and returns a string.

A:
  1. void igor(void); // or void igor()

  2. float tofu(int n); // or float tofu(int);

  3. double mpg(double miles, double gallons);

  4. long summation(long harray[], int size);

  5. double doctor(const char * str);

  6. void ofcourse(boss dude);

  7. char * plot(map *pmap);

3:

Write a function that takes three arguments: the name of an int array, the array size, and an int value. Have the function set each element of the array to the int value.

A:
void set_array(int arr[], int size, int value)
{
    for (int i = 0; i < size; i++)
        arr[i] = value;
}
4:

Write a function that takes three arguments: a pointer to the first element of a range in an array, a pointer to the element following the end of a range in an array, and an int value. Have the function set each element of the array to the int value.

A:
void set_array(int * begin, int * end, int value)
{
    for (int * pt = begin; pt != end; pt++)
        pt* = value;
}
5:

Write a function that takes a double array name and an array size as arguments and returns the largest value in that array. Note that this function shouldn't alter the contents of the array.

A:
double biggest (const double foot[], int size)
{
    double max;
    if (size < 1)
    {
        cout << "Invalid array size of " << size << "\n";
        cout << "Returning a value of 0\n";
        return 0;
    }
    else    // not necessary because return terminates program
    {
        max = foot[0];
        for (int i = 1; i < size; i++)
            if (foot[i] > max)
                max = foot[i];
        return max;
    }
}
6:

Why don't we use the const qualifier for function arguments that are one of the fundamental types?

A:

We use the const qualifier with pointers to protect the original pointed-to data from being altered. When a program passes a fundamental type such as an int or double, it passes it by value so that the function works with a copy. Thus, the original data is already protected.

7:

What are the three forms a C-style string can take in a C++ program?

A:

A string can be stored in a char array, it can be represented by a string constant in double quotation marks, and it can be represented by a pointer pointing to the first character of a string.

8:

Write a function that has this prototype:

int replace(char * str, char c1, char c2);

Have the function replace every occurrence of c1 in the string str with c2, and have the function return the number of replacements it makes.

9:

What does the expression *"pizza" mean? What about "taco"[2]?

A:
int replace(char * str, char c1, char c2)
{
    int count = 0;
    while (*str)      // while not at end of string
    {
        if (*str == c1)
        {
            *str = c2;
            count++;
        }
        str++;        // advance to next character
    }
    return count;
}
10:

What does the expression *"pizza" mean? What about "taco"[2]?

A:

Because C++ interprets "pizza" as the address of its first element, applying the * operator yields the value of that first element, which is the character p. Because C++ interprets "taco" as the address of its first element, it interprets "taco"[2] as the value of the element two positions down the line, that is, as the character c. In other words, the string constant acts the same as an array name.

11:

C++ enables you to pass a structure by value and it lets you pass the address of a structure. If glitz is a structure variable, how would you pass it by value? How would you pass its address? What are the trade-offs of the two approaches?

A:

To pass it by value, just pass the structure name glitz. To pass its address, use the address operator &glitz. Passing by value automatically protects the original data, but it takes time and memory. Passing by address saves time and memory but doesn't protect the original data unless you use the const modifier for the function parameter. Also, passing by value means you can use ordinary structure member notation, but passing a pointer means you have to remember to use the indirect membership operator.

12:

The function judge() has a type int return value. As an argument, it takes the address of a function that takes a pointer to a const char as an argument and that also returns an int. Write the function prototype.

A:
int judge (int (*pf)(const char *));

Chapter 8

1:

What kinds of functions are good candidates for inline status?

A:

Short, non-recursive functions that can fit in one line of code.

2:

Suppose the song() function has this prototype:

void song(char * name, int times);
  1. How would you modify the prototype so that the default value for times is 1?

  2. What changes would you make in the function definition?

  3. Can you provide a default value of "O, My Papa" for name?

A:
  1. void song(char * name, int times = 1);

  2. None. Only prototypes contain the default value information.

  3. Yes, providing you retain the default value for times:

    void song(char * name = "O, My Papa", int times = 1);
3:

Write overloaded versions of iquote(), a function that displays its argument enclosed in double quotation marks. Write three versions: one for an int argument, one for a double argument, and one for a string argument.

A:

You can use either the string "\"" or the character '"' to print a quotation mark. The following functions show both methods.

#include <iostream.h>
void iquote(int n)
{
    cout << "\"" << n << "\"";
}
void iquote(double x)
{
    cout << '"' << x << '"';
}
void iquote(const char * str)
{
    cout << "\"" << str << "\"";
}
4:

Here is a structure template:

A:
  1. This function shouldn't alter the structure members, so use the const qualifier.

    void show_box(const box & container)
    {
        cout << "Made by " << container. maker << "\n";
        cout << "Height = " << container.height << "\n";
        cout << "Width = " << container.width << "\n";
        cout << "Length = " << container.length << "\n";
        cout << "Volume = " << container.volume << "\n";
    }
    
  2.  

    void set_volume(box & crate)
    {
        crate.volume = crate.height * crate.width * crate.length;
    }
    
5:

Here are some desired effects. Indicate whether each can be accomplished with default arguments, function overloading, both, or neither. Provide appropriate prototypes.

  1. mass(density, volume) returns the mass of an object having a density of density and a volume of volume, whereas mass(density) returns the mass having a density of density and a volume of 1.0 cubic meters. All quantities are type double.

  2. repeat(10, "I'm OK") displays the indicated string ten times, whereas repeat("But you're kind of stupid") displays the indicated string five times.

  3. average(3,6) returns the int average of two int arguments, whereas average(3.0, 6.0) returns the double average of two double values.

  4. mangle("I'm glad to meet you") returns the character I or a pointer to the string "I'm mad to gleet you" depending on whether you assign the return value to a char variable or to a char* variable.

A:
  1. This can be done using a default value for the second argument:

    double mass(double d, double v = 1.0);
    

    It can also be done by overloading:

    double mass(double d, double v);
    double mass(double d);
    
  2. You can't use a default for the repeat value because you have to provide default values from right to left. You can use overloading:

    void repeat(int times, const char * str);
    void repeat(const char * str);
    
  3. You can use function overloading:

    int average(int a, int b);
    double average(double x, double y);
    
  4. You can't do this one because both versions would have the same signature.

6:

Write a function template that returns the larger of its two arguments.

A:
template<class T>
T max(T t1, T t2)  // or T max(const T & t1, const T & t2)
{
    return t1 > t2? t1 : t2;
}
7:

Given the template of Review Question 6 and the box structure of Review Question 4, provide a template specialization that takes two box arguments and returns the one with the larger volume.

A:
template<> box max(box b1, box b2)
{
    return b1.volume > b2.volume? b1 : b2;
}

Chapter 9

1:

What storage scheme would you use for the following situations?

  1. homer is a formal argument (parameter) to a function.

  2. The secret variable is to be shared by two files.

  3. The topsecret variable is to be shared by the functions in one file but hidden from other files.

  4. beencalled keeps track of how many times the function containing it has been called.

A:
  1. homer is automatically an automatic variable.

  2. secret should be defined as an external variable in one file and declared using extern in the second file.

  3. topsecret could be defined as a static variable with internal linkage by prefacing the external definition with the keyword static. Or it could be defined in an unnamed namespace.

  4. beencalled should be defined as a local static variable by prefacing a declaration in the function with the keyword static.

2:

Discuss the differences between a using-declaration and a using-directive.

A:

A using declaration makes a single name from a namespace available, and it has the scope corresponding to the declarative region in which the using declaration occurs. A using directive makes all the names in a namespace available. When you use a using directive, it is as if you declared the names in the smallest declarative region containing both the using declaration and the namespace itself.

3:

Rewrite the following so that it doesn't use using-declarations or using-directives.

#include <iostream>
using namespace std;
int main()
{
    double x;
    cout << "Enter value: ";
    while (! (cin >> x) )
    {
        cout << "Bad input. Please enter a number: ";
        cin.clear();
       while (cin.get() != '\n')
           continue;
    }
    cout << "Value = " << x << endl;
    return 0;
}
A:
#include <iostream>
using namespace std;
int main()
{
    double x;
    std::cout << "Enter value: ";
    while (! (std::cin >> x) )
    {
        std::cout << "Bad input. Please enter a number: ";
        std::cin.clear();
       while (std::cin.get() != '\n')
           continue;
    }
    std::cout << "Value = " << x << std::endl;
    return 0;
}
4:

Rewrite the following so that it uses using-declarations instead of the using-directive.

#include <iostream>
using namespace std;
int main()
{
    double x;
    cout << "Enter value: ";
    while (! (cin >> x) )
    {
        cout << "Bad input. Please enter a number: ";
        cin.clear();
       while (cin.get() != '\n')
           continue;
    }
    cout << "Value = " << x << endl;
    return 0;
}
A:

Rewrite the following so that it uses using declarations instead of the using directive.

#include <iostream>
int main()
{
    using std::cin;
    using std::cout;
    using std::endl;
    double x;
    cout << "Enter value: ";
    while (! (cin >> x) )
    {
        cout << "Bad input. Please enter a number: ";
        cin.clear();
       while (cin.get() != '\n')
           continue;
    }
    cout << "Value = " << x << endl;
    return 0;
}
5:

The average(3,6) function returns an int average of the two int arguments when called in one file, and it returns a double average of the two int arguments when called in a second file in the same program. How could you set this up?

A:

You could have separate static function definitions in each file. Or each file could define the appropriate average() function in an unnamed namespace.

6:

What will the following two-file program display?

// file1.cpp
#include <iostream>
using namespace std;
void other();
void another();
int x = 10;
int y;
int main()
{
    cout << x << endl;
    {
        int x = 4;
        cout << x << endl;
        cout << y << endl;
    }
    other();
    another();
    return 0;
}
void other()
{
    int y = 1;
    cout << "Other: " << x << "," << y << endl;
}
// file 2.cpp
#include <iostream>
using namespace std;
extern int x;
namespace
{
     int y = -4;
}
void another()
{
    cout << "another(): " << x << ", " << y << endl;
}
A:
10
4
0
Other: 10, 1
another(): 10, -4
7:

What will the following program display?

#include <iostream>
using namespace std;
void other();
namespace n1
{
    int x = 1;
}
namespace n2
{
    int x = 2;
}
int main()
{
   using namespace n1;
   cout << x << endl;
    {
        int x = 4;
        cout << x << ", " << n1::x << ", " << n2::x << endl;
    }
    using n2::x;
    cout << x << endl;
    other();
    return 0;
}
void other()
{
    using namespace n2;
    cout << x << endl;
    {
        int x = 4;
        cout << x << ", " << n1::x << ", " << n2::x << endl;
    }
    using n2::x;
    cout << x << endl;
}
A:
1
4, 1, 2
2
2
4, 1, 2
2

Chapter 10

1:

What is a class?

A:

A class is a definition of a user-defined type. A class declaration specifies how data is to be stored, and it specifies the methods (class member functions) that can be used to access and manipulate that data.

2:

How does a class accomplish abstraction, encapsulation, and data hiding?

A:

A class represents the operations one can perform on a class object with a public interface of class methods; this is abstraction. The class can use private visibility (the default) for data members, meaning that the data can be accessed only through the member functions; this is data hiding. Details of the implementation, such as data representation and method code, are hidden; this is encapsulation.

3:

What is the relationship between an object and a class?

A:

The class defines a type, including how it can be used. An object is a variable or other data object, such as that produced by new, created and used according to the class definition. The relationship is the same as that between a standard type and a variable of that type.

4:

In what way, aside from being functions, are class function members different from class data members?

A:

If you create several objects of a given class, each object comes with storage for its own set of data. But all the objects use the one set of member functions. (Typically, methods are public and data members are private, but that's a matter of policy, not of class requirements.)

Note

graphics/common.gif

The program uses cin.get(char *, int) instead of cin >> to read names because cin.get() reads a whole line instead of just one word (see Chapter 4).

5:

Define a class to represent a bank account. Data members should include the depositor's name, the account number (use a string), and the balance. Member functions should allow the following:

  • Creating an object and initializing it.

  • Displaying the depositor's name, account number, and balance

  • Depositing an amount of money given by an argument

  • Withdrawing an amount of money given by an argument

Just show the class declaration, not the method implementations. (Programming Exercise 1 provides you with an opportunity to write the implementation.)

A:
#include <iostream>
using namespace std;
// class definition
class BankAccount
{
private:
    char name[40];
    char acctnum[25];
    double balance;
public:
    BankAccount(const char * client = "X", const char * num = "X", double bal = 0;)
    void show(void) const;
    void deposit(double cash);
    void withdraw(double cash);
};
6:

When are class constructors called? When are class destructors called?

A:

A class constructor is called when you create an object of that class or when you explicitly call the constructor. The class destructor is called when the object expires.

7:

Provide code for a constructor for the bank account class of question 5.

A:

Note that you must include cstring or string.h in order to use strncpy().

BankAccount::BankAccount(const char * client, const char * num, double bal)
{
    strccpy(name, client, 39);
    name[39] = '\0';
    strncpy(acctnum, num, 24);
    acctnum[24] = '\0';
    balance = bal;
}

Keep in mind that default arguments go in the prototype, not in the function definition.

8:

What is a default constructor and what's the advantage of having one?

A:

A default constructor is one with no arguments or else with defaults for all the arguments. Having one enables you to declare objects without initializing them, even if you've already defined an initializing constructor. It also allows you to declare arrays.

9:

Modify the Stock class (the version in stock2.h) so that it has member functions that return the values of the individual data members. Note: A member that returns the company name should not provide a weapon for altering the array. That is, it can't simply return a char *. It could return a const pointer, or it could return a pointer to a copy of the array, manufactured by using new.

A:
// stock3.h
#ifndef STOCK3_H_
#define STOCK3_H_
class Stock
{
private:
    char company[30];
    int shares;
    double share_val;
    double total_val;
    void set_tot() { total_val = shares * share_val; }
public:
    Stock();            // default constructor
    Stock(const char * co, int n, double pr);
    ~Stock() {}          // do-nothing destructor
    void buy(int num, double price);
    void sell(int num, double price);
    void update(double price);
    void show() const;
    const Stock & topval(const Stock & s) const;
    int numshares() const { return shares; }
    double shareval() const { return share_val; }
    double totalval() const { return total_val; }
    const char * co_name() const { return company; }
};
10:

What are this and *this?

A:

The this pointer is a pointer available to class methods. It points to the object used to invoke the method. Thus, this is the address of the object, and *this represents the object itself.

Chapter 11

1:

Use a member function to overload the multiplication operator for the Stonewt class; have the operator multiply the data members by a type double value. Note that this will require carryover for the stone-pound representation. That is, twice 10 stone 8 pounds is 21 stone 2 pounds.

A:

Here's a prototype for the class definition file and a function definition for the methods file:

// prototype
Stonewt operator*(double mult);
// definition -- let constructor do the work
Stonewt Stonewt::operator*(double mult)
{
    return Stonewt(mult * pounds);
}
2:

What are the differences between a friend function and a member function?

A:

A member function is part of a class definition and is invoked by a particular object. The member function can access members of the invoking object implicitly, without using the membership operator. A friend function is not part of a class, so it's called as a straight function call. It can't access class members implicitly, so it must use the membership operator applied to an object passed as an argument. Compare, for instance, the answer to Review Question 1 with the answer to Review Question 4.

3:

Does a nonmember function have to be a friend to access a class's members?

A:

It must be a friend to access private members, but it doesn't have to be a friend to access public members.

4:

Use a friend function to overload the multiplication operator for the Stonewt class; have the operator multiply the double value by the Stone value.

A:

Here's a prototype for the class definition file and a function definition for the methods file:

// prototype
friend Stonewt operator*(double mult, const Stonewt & s);
// definition -- let constructor do the work
Stonewt operator*(double mult, const Stonewt & s)
{
    return Stonewt(mult * s.pounds);
}
5:

Which operators cannot be overloaded?

A:

The following five operators cannot be overloaded:

sizeof   .   .*   ::   ? :
6:

What restriction applies to overloading the following operators? = () [] ->

A:

These operators must be defined by using a member function.

7:

Define a conversion function for the Vector class that converts a Vector to a type double value representing the vector's magnitude.

A:

Here is a possible prototype and definition:

// prototype and inline definition
operator double () {return mag;}

Note, however, that it makes better sense to use the magval() method than to define this conversion function.

Chapter 12

1:

Suppose a String class has the following private members:

class String
{
private:
    char * str;    // points to string allocated by new
    int len;       // holds length of string
//...
} ;
  1. What's wrong with this default constructor?

    String::String() { }
    
  2. What's wrong with this constructor?

    String::String(const char * s)
    {
        str = s;
        len = strlen(s);
    }
    
  3. What's wrong with this constructor?

    String::String(const char * s)
    {
        strcpy(str, s);
        len = strlen(s);
    }
    
A:
  1. The syntax is fine, but this constructor leaves the str pointer uninitialized. The constructor should either set the pointer to NULL or use new [] to initialize the pointer.

  2. This constructor does not create a new string; it merely copies the address of the old string. It should use new [] and strcpy().

  3. It copies the string without allocating the space to store it. It should use new char[len + 1] to allocate the proper amount of memory.

2:

Name three problems that may arise if you define a class in which a pointer member is initialized using new and indicate how they can be remedied.

A:

First, when an object of that type expires, the data pointed to by the object's member pointer remains in memory, using space and remaining inaccessible because the pointer has been lost. That can be fixed by having the class destructor delete memory allocated by new in the constructor functions. Second, once the destructor deletes such memory, it may wind up trying to delete it twice if a program initialized one such object to another. That's because the default initialization of one object to another copies pointer values but does not copy the pointed-to data, producing two pointers to the same data. The solution is to define a class copy constructor that causes initialization to copy the pointed-to data. Third, assigning one object to another can produce the same situation of two pointers pointing to the same data. The solution is to overload the assignment operator so that it copies the data, not the pointers.

3:

What class methods does the compiler generate automatically if you don't provide them explicitly? Describe how these implicitly generated functions behave.

A:

C++ automatically provides the following member functions:

  • A default constructor if you define no constructors

  • A copy constructor if you don't define one

  • An assignment operator if you don't define one

  • A default destructor if you don't define one

  • An address operator if you don't define one

The default constructor does nothing, but it allows you to declare arrays and uninitialized objects. The default copy constructor and the default assignment operator use memberwise assignment. The default destructor does nothing. The implicit address operator returns the address of the invoking object (that is, the value of the this pointer).

4:

Identify and correct errors in the following class declaration:

class nifty
{
// data
    char personality[];
    int talents;
// methods
    nifty();
    nifty(char * s);
    ostream & operator<<(ostream & os, nifty & n);
}
nifty:nifty()
{
    personality = NULL;
    talents = 0;
}
nifty:nifty(char * s)
{
    personality = new char [strlen(s)];
    personality = s;
    talents = 0;
}
ostream & nifty:operator<<(ostream & os, nifty & n)
{
    os << n;
}
A:

The personality member should be declared either as a character array or as a pointer-to-char. Or you could make it a String object. Here are two possible solutions, with changes (other than deletions) in boldface.

#include <iostream>
#include <cstring>
using namespace std;
class nifty
{
private: // optional
    char personality[40];    // provide array size
    int talents;
public: // needed
// methods
    nifty();
    nifty(const char * s);
    friend ostream & operator<<(ostream & os, const nifty & n);
};    // note closing semicolon
nifty::nifty()
{
    personality[0] = '\0';
    talents = 0;
}
nifty::nifty(const char * s)
{
    strcpy(personality, s);
    talents = 0;
}
ostream & operator<<(ostream & os, const nifty & n)
{
    os << n.personality << '\n';
    os << n.talent << '\n';
    return os;
}

Or you could do this:

#include <iostream>
#include <cstring>
using namespace std;
class nifty
{
private: // optional
    char * personality;    // create a pointer
    int talents;
public: // needed
// methods
    nifty();
    nifty(const char * s);
    nifty(const nifty & n);
    ~nifty() { delete personality; }
    nifty & operator=(const nifty & n) const;
    friend ostream & operator<<(ostream & os, const nifty & n);
};    // note closing semicolon
nifty::nifty()
{
    personality = NULL;
    talents = 0;
}
nifty::nifty(const char * s)
{
    personality = new char [strlen(s) + 1];
    strcpy(personality, s);
    talents = 0;
}
ostream & operator<<(ostream & os, const nifty & n)
{
    os << n.personality << '\n';
    os << n.talent << '\n';
    return os;
}
5:

Consider the following class declaration:

class Golfer
{
private:
    char * fullname;       // points to string containing golfer's name
    int games;             // holds number of golf games played
    int * scores;          // points to first element of array of golf scores
public:
    Golfer();
    Golfer(const char * name, int g= 0);
     // creates empty dynamic array of g elements if g > 0
    Golfer(const Golfer & g);
    ~Golfer();
} ;
  1. What class methods would be invoked by each of the following statements?

    Golfer nancy;                        // #1
    Golfer lulu("Little Lulu");          // #2
    Golfer roy("Roy Hobbs", 12);         // #3
    Golfer * par = new Golfer;           // #4
    Golfer next = lulu;                  // #5
    Golfer hazzard = "Weed Thwacker";    // #6
    *par = nancy;                        // #7
    nancy = "Nancy Putter";              // #8
    
  2. Clearly, the class requires several more methods to make it useful, but what additional method does it require to protect against data corruption?

A:
  1.  

    Golfer nancy; // default constructor
    Golfer lulu("Little Lulu"); // Golfer(const char * name, int g)
    Golfer roy("Roy Hobbs", 12); // Golfer(const char * name, int g)
    Golfer * par = new Golfer; // default constructor
    Golfer next = lulu; // Golfer(const Golfer &g)
    Golfer hazard = "Weed Thwacker"; // Golfer(const char * name, int g)
    *par = nancy; // default assignment operator
    nancy = "Nancy Putter";// Golfer(const char * name, int g), then
                           // the default assignment operator
    

    Note

    graphics/common.gif

    Some compilers will additionally call the default assignment operator for statements #5 and #6.

  2. The class should define an assignment operator that copies data rather than addresses.

Chapter 13

1:

What does a derived class inherit from a base class?

A:

The public members of the base class become public members of the derived class. The protected members of the base class become protected members of the derived class. The private members of the base class are inherited, but cannot be accessed directly. The answer to review question 2 provides the exceptions to these general rules.

2:

What doesn't a derived class inherit from a base class?

A:

The constructor methods are not inherited, the destructor is not inherited, the assignment operator is not inherited, and friends are not inherited.

3:

Suppose the return type for the baseDMA::operator=() function were defined as void instead of baseDMA &. What effect, if any, would that have? What if the return type were baseDMA instead of baseDMA &?

A:

If the return type were void, you would still be able to use single assignment but not chain assignment:

baseDMA magazine("Pandering to Glitz", 1);
baseDMA gift1, gift2, gift3;
gift1 = magazine;         // ok
gift 2 = gift3 = gift1;  // no longer valid

If the method returned an object instead of a reference, the method execution would be slowed a bit because the return statement would involve copying the object.

4:

In what order are class constructors and class destructors called when a derived class object is created and deleted?

A:

Constructors are called in the order of derivation, with the most ancestral constructor called first. Destructors are called in the opposite order.

5:

If a derived class doesn't add any data members to the base class, does the derived class require constructors?

A:

Yes, every class requires its own constructors. If the derived class adds no new members, the constructor can have an empty body, but it must exist.

6:

Suppose a base class and a derived class both define a method of the same name and a derived class object invokes the method. What method is called?

A:

Only the derived class method is called. It supersedes the base class definition. A base class method is called only if the derived class does not redefine the method or if you use the scope resolution operator. However, you really should declare as virtual any functions that will be redefined.

7:

When should a derived class define an assignment operator?

A:

The derived class should define an assignment operator if the derived class constructors use the new or new [] operator to initialize pointers that are members of that class. More generally, the derived class should define an assignment operator if the default assignment is incorrect for derived class members.

8:

Can you assign the address of an object of a derived class to a pointer to the base class? Can you assign the address of an object of a base class to a pointer to the derived class?

A:

Yes, you can assign the address of an object of a derived class to a pointer to the base class. You can assign the address of a base object to a pointer to a derived class (downcasting) only by making an explicit type cast, and it is not necessarily safe to use such a pointer.

9:

Can you assign an object of a derived class to an object of the base class? Can you assign an object of a base class to an object of the derived class?

A:

Yes, you can assign an object of a derived class to an object of the base class. Any data members new to the derived type are not passed to the base type, however. The program will use the base class assignment operator. Assignment in the opposite direction (base to derived) is possible only if the derived class defines a conversion operator, which is a constructor having a reference to the base type as its sole argument, or else defines an assignment operator with a base-class parameter.

10:

Suppose you define a function that takes a reference to a base class object as an argument. Why can this function also use a derived class object as an argument?

A:

It can do so because C++ allows a reference to a base type to refer to any type derived from that base.

11:

Suppose you define a function that takes a base class object as an argument (that is, the function passes a base class object by value). Why can this function also use a derived class object as an argument?

A:

Passing an object by value invokes the copy constructor. Since the formal argument is a base class object, the base class copy constructor is invoked. The copy constructor has as its argument a reference to the base class, and this reference can refer to the derived object passed as an argument. The net result is producing a new base class object whose members correspond to the base class portion of the derived object.

12:

Why is it usually better to pass objects by reference than by value?

A:

Passing an object by reference instead of by value enables the function to avail itself of virtual functions. Also, passing an object by reference instead of value may use less memory and time, particularly for large objects. The main advantage of passing by value is that it protects the original data, but you can accomplish the same end by passing the reference as a const type.

13:

Suppose Corporation is a base class and PublicCorporation is a derived class. Also suppose that each class defines a head() member function, that ph is a pointer to the Corporation type, and that ph is assigned the address of a PublicCorporation object. How is ph->head() interpreted if the base class defines head() as a

  1. Regular nonvirtual method

  2. Virtual method

A:

If head() is a regular method, then ph->head() invokes Corporation::head(). If head() is a virtual function, then ph->head() invokes PublicCorporation::head().

14:

What's wrong, if anything, with the following code?

class Kitchen
{
private:
    double kit_sq_ft;
public:
    Kitchen() { kit_sq_ft = 0.0; }
    virtual double area() {  return kit_sq_ft * kit_sq_ft; }
};
class House : public Kitchen
{
private:
    double all_sq_ft;
public:
    House() { all_sq_ft += kit_sq_ft;}
    double area(const char *s) {  cout << s; return all_sq_ft; }
};
A:

First, the situation does not fit the is-a model, so public inheritance is not appropriate. Second, the definition of area() in House hides the Kitchen version of area() because the two methods have different signatures.

Chapter 14

1:

For each of the following sets of classes, indicate whether public or private derivation is more appropriate for the second column:

class Bear class PolarBear
class Kitchen class Home
class Person class Programmer
class Person class HorseAndJockey
class Person, class Automobile class Driver
A:  
class Bear class PolarBear Public, a polar bear is a kind of bear
class Kitchen class Home Private, a home has a kitchen
class Person class Programmer Public, a programmer is a kind of person
class Person class HorseAndJockey Private, a horse and jockey team contains aperson
class Person, class class Driver Automobile Person public because a driver is a person; Automobile private because a driver has an automobile
2:

Suppose we have the following definitions:

class Frabjous {
private:
      char fab[20];
public:
      Frabjous(const char * s = "C++") : fab(s) {}
      virtual void tell() { cout << fab; }
};
class Gloam {
private:
      int glip;
      Frabjous fb;
public:
      Gloam(int g = 0, const char * s = "C++");
      Gloam(int g, const Frabjous & f);
      void tell();
};

Given that the Gloam version of tell() should display the values of glip and fb, provide definitions for the three Gloam methods.

A:
Gloam::Gloam(int g, const char * s) : glip(g), fb(s) { }
Gloam::Gloam(int g, const Frabjous & f) : glip(g), fb(f) { }
// note: the above uses the default Frabjous copy constructor
void Gloam::tell()
{
    fb.tell();
    cout << glip << '\n';
}
3:

Suppose we have the following definitions:

class Frabjous {
private:
      char fab[20];
public:
      Frabjous(const char * s = "C++") : fab(s) {}
      virtual void tell() { cout << fab; }
};
class Gloam : private Frabjous{
private:
      int glip;
public:
      Gloam(int g = 0, const char * s = "C++");
      Gloam(int g, const Frabjous & f);
      void tell();
};

Given that the Gloam version of tell() should display the values of glip and fab, provide definitions for the three Gloam methods.

A:
Gloam::Gloam(int g, const char * s)
             : glip(g), Frabjous(s) { }
Gloam::Gloam(int g, const Frabjous & f)
             : glip(g), Frabjous(f) { }
// note: the above uses the default Frabjous copy constructor
void Gloam::tell()
{
    Frabjous::tell();
    cout << glip << '\n';
}
4:

Suppose we have the following definition, based on the Stack template of Listing 14.14 and the Worker class of Listing 14.11:

Stack<Worker *> sw;

Write out the class declaration that will be generated. Just do the class declaration, not the non-inline class methods.

A:
class Stack<Worker *>
{
private:
    enum {MAX = 10};        // constant specific to class
    Worker * items[MAX];    // holds stack items
    int top;                // index for top stack item
public:
    Stack();
    Boolean isempty();
    Boolean isfull();
    Boolean push(const Worker * & item); // add item to stack
    Boolean pop(Worker * & item);        // pop top into item
};
5:

Use the template definitions in this chapter to define the following:

  • An array of String objects

  • A stack of arrays of double

  • An array of stacks of pointers to Worker objects

How many template class definitions are produced in Listing 14.19?

A:
ArrayTP<String> sa;
StackTP< ArrayTP<double> > stck_arr_db;
ArrayTp< StackTP<Worker *> > arr_stk_wpr;
6:

Describe the differences between virtual and nonvirtual base classes.

A:

If two lines of inheritance for a class share a common ancestor, the class winds up with two copies of the ancestor's members. Making the ancestor class a virtual base class to its immediate descendants solves that problem.

Chapter 15

1:

What's wrong with the following attempts at establishing friends?

  1. class snap {
        friend clasp;
         ...
    } ;
    class clasp {  ... } ;
    
  2. class cuff {
    public:
          void snip(muff &) {  ... }
          ...
    } ;
    class muff {
         friend void cuff::snip(muff &);
         ...
    } ;
    
  3. class muff {
          friend void cuff::snip(muff &);
         ...
    } ;
    class cuff {
    public:
          void snip(muff &) {  ... }
          ...
    } ;
A:
  1. The friend declaration should be as follows:

    friend class clasp;
    
  2. This needs a forward declaration so that the compiler can interpret void snip(muff &):

    class muff;    // forward declaration
    class cuff {
    public:
        void snip(muff &) { ... }
        ...
    };
    class muff {
        friend void cuff::snip(muff &);
        ...
    };
    
  3. First, the cuff class declaration should precede the muff class so that the compiler can understand the term cuff::snip(). Second, the compiler needs a forward declaration of muff so that it can understand snip(muff &).

    class muff;    // forward declaration
    class cuff {
    public:
        void snip(muff &) { ... }
        ...
    };
    class muff {
        friend void cuff::snip(muff &);
        ...
    };
    
2:

You've seen how to create mutual class friends. Can you create a more restricted form of friendship in which only some members of class B are friends to class A and some members of A are friends to B? Explain.

A:

No. For A to have a friend that's a member function of B, the B declaration must precede the A declaration. A forward declaration is not enough, for it would tell A that B is a class, but it wouldn't reveal the names of the class members. Similarly, if B has a friend that's a member function of A, the complete A declaration must precede the B declaration. These two requirements are mutually exclusive.

3:

What problems might the following nested class declaration have?

class Ribs
{
private:
    class Sauce
    {
          int soy;
          int sugar;
   public:
          Sauce(int s1, int s2) : soy(s1), sugar(s2) {  }
   } ;
   ...
} ;
A:

The only access to a class is through its public interface, which means the only thing you can do with a Sauce object is call the constructor to create one. The other members (soy and sugar) are private by default.

4:

How does throw differ from return?

A:

Suppose function f1() calls function f2(). A return statement in f2() causes program execution to resume at the next statement following the f2() function call in function f1(). A throw statement causes the program to back up through the current sequence of function calls until it finds a try block that directly or indirectly contains the call to f2(). This might be in f1() or in a function that called f1(), and so on. Once there, execution goes to the next matching catch block, not to the first statement after the function call.

5:

Suppose you have a hierarchy of exception classes derived from a base exception class. In what order should you place catch blocks?

A:

You should arrange the catch blocks in the order of most derived class to least derived.

6:

Consider the Grand, Superb, and Magnificent classes defined in this chapter. Suppose pg is a type Grand * pointer assigned the address of an object of one of these three classes and that ps is a type Superb * pointer. What is the difference in how the following two code samples behave?

if (ps = dynamic_cast<Superb *>(pg))
    ps->say();  // sample #1
if (typeid(*pg) == typeid(Superb))
    (Superb *) pg)->say();  // sample #2
A:

For sample #1, the if condition is true if pg points to a Superb object or to an object of any class descended from Superb. In particular, it is also true if pg points to a Magnificent object. In sample #2, the if condition is true only for a Superb object, not for objects derived from Superb.

7:

How is the static_cast operator different from the dynamic_cast operator?

A:

The dynamic_cast operator only allows upcasting in a class hierarchy, while a static_cast operator allows both upcasting and downcasting. The static_cast operator also allows conversions from enumeration types to integer types, and vice versa, and between various numeric types.

Chapter 16

1:

Consider the following class declaration:

class RQ1
{
private:
    char * st;       // points to C-style string
public:
    RQ1() { st = new char [1]; strcpy(st,""); }
    RQ1(const char * s)
    {st = new char [strlen(s) + 1]; strcpy(st, s); }
    RQ1(const RQ1 & rq)
    {st = new char [strlen(rq.st) + 1]; strcpy(st, rq.st); }
    ~RQ1() {delete [] st};
    RQ & operator=(const RQ & rq);
    // more stuff
};

Convert this to a declaration using a string object instead. What methods no longer need an explicit definition?

A:
#include <string>
using namespace std;
class RQ1
{
private:
    string st;       // a string object
public:
    RQ1() : st("") {}
    RQ1(const char * s) : st(s) {}
    ~RQ1() {};
// more stuff
};

The explicit copy constructor, destructor, and assignment operator no longer are needed because the string object provides its own memory management.

2:

Name at least two advantages string objects have over C-style strings in terms of ease-of-use.

A:

You can assign one string object to another. A string object provides its own memory management so that you normally don't have to worry about a string exceeding the capacity of its holder.

3:

Write a function that takes a reference to a string as an argument and which converts the string to all uppercase.

A:
#include <string>
#include <cctype>
using namespace std;
void ToUpper(string & str)
{
    for (int i = 0; i < str.size(); i++)
        str[i] = toupper(str[i]);
}
4:

Which of the following are not examples of correct usage (conceptually or syntactically) of auto_ptr? (Assume the needed header files have been included.)

auto_ptr<int> pia(new int[20]);
auto_ptr<str> (new string);
int rigue = 7;
auto_ptr<int>pr(&rigue);
auto_ptr dbl (new double);
A:
auto_ptr<int> pia= new int[20];  // wrong, use with new, not new[]
auto_ptr<str>(new string);       // wrong, no name for pointer
int rigue = 7;
auto_ptr<int>(&rigue);           // wrong, memory not allocated by new
auto_ptr dbl (new double);       // wrong, omits <double>
5:

If you could make the mechanical equivalent of a stack that held golf clubs instead of numbers, why would it (conceptually) be a bad golf bag?

A:

The LIFO aspect of a stack means you might have to remove a lot of clubs before reaching the one you need.

6:

Why would a set container be a poor choice for storing a hole-by-hole record of your golf scores?

A:

The set will store just one copy of each value, so, say, five scores of 5 would be stored as a single 5.

7:

Because a pointer is an iterator, why didn't the STL designers simply use pointers instead of iterators?

A:

Using iterators allows one to use objects with a pointer-like interface to move through data organized in fashions other than an array; for example, data in a doubly linked list.

8:

Why didn't the STL designers simply define a base iterator class, use inheritance to derive classes for the other iterator types, and express the algorithms in terms of those iterator classes?

A:

The STL approach lets STL functions be used with ordinary pointers to ordinary arrays as well as with iterators to STL container classes, thus increasing generality.

9:

Give at least three examples of convenience advantages that a vector object has over an ordinary array.

A:

You can assign one vector object to another. A vector manages its own memory, so you can insert items into a vector and have it resize itself automatically. By using the at() method, you can get automatic bounds checking.

10:

If Listing 16.6 were implemented with list instead of vector, what parts of the program would become invalid? Could the invalid part be fixed easily? If so, how?

A:

The two sort() functions and the random_shuffle() function require a random-access iterator, while a list object just has a bidirectional iterator. You can use the list template class sort() member functions instead of the general purpose functions to do the sorting, but there is no member function equivalent to random_shuffle(). However, you could copy the list to a vector, shuffle the vector, and copy the results back to the list. (At the time of this writing, most compilers have not yet implemented the sort() member function that takes a Compare object as its argument. Also, the Microsoft Visual C++ 6.0 implementation of the list class has some bugs that prevent making the suggested conversions.

Chapter 17

1:

What role does the iostream file play in C++ I/O?

A:

The iostream file defines the classes, constants, and manipulators used to manage input and output. These objects manage the streams and buffers used to handle I/O. The file also creates standard objects (cin, cout, cerr, and clog and their wide-character equivalents) used to handle the standard input and output streams connected to every program.

2:

Why does typing a number such as 121 as input require a program to make a conversion?

A:

Keyboard entry generates a series of characters. Typing 121 generates three characters, each represented by a 1-byte binary code. If the value is to be stored as type int, these three characters have to be converted to a single binary representation of the value 121.

3:

What's the difference between the standard output and the standard error?

A:

By default, both the standard output and the standard error send output to the standard output device, typically a monitor. If you have the operating system redirect output to a file, however, the standard output connects to the file instead of to the screen, but the standard error continues to be connected to the screen.

4:

Why is cout able to display various C++ types without being provided explicit instructions for each type?

A:

The ostream class defines a version of the operator<<() function for each basic C++ type. The compiler interprets an expression like

cout << spot

as the following:

cout.operator<<(spot)

It then can match this method call to the function prototype having the same argument type.

5:

What feature of the output method definitions allows you to concatenate output?

A:

You can concatenate output methods that return type ostream &. This causes the invoking of a method with an object to return that object. The returned object can then invoke the next method in a sequence.

6:

Write a program that requests an integer and then displays it in decimal, octal, and hexadecimal form. Display each form on the same line in fields that are 15 characters wide, and use the C++ number base prefixes.

A:
//rq17-6.cpp
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
    cout << "Enter an integer: ";
    int n;
    cin >> n;
    cout << setw(15) << "base ten" << setw(15)
           << "base sixteen" << setw(15) << "base eight" << "\n";
    cout.setf(ios::showbase);    // or cout << showbase;
    cout << setw(15) << n << hex << setw(15) << n
           << oct << setw(15) << n << "\n";
    return 0;
}
7:

Write a program that requests the information shown below and that formats it as shown:

Enter your name: Billy Gruff
Enter your hourly wages: 12
Enter number of hours worked: 7.5
First format:
                   Billy Gruff: $     12.00:  7.5
Second format:
Billy Gruff                   : $12.00     :7.5
A:
//rq17-7.cpp
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
    char name[20];
    float hourly;
    float hours;
    cout << "Enter your name: ";
    cin.get(name, 20).get();
    cout << "Enter your hourly wages: ";
    cin >> hourly;
    cout << "Enter number of hours worked: ";
    cin >> hours;
    cout.setf(ios::showpoint);
    cout.setf(ios::fixed, ios::floatfield);
    cout.setf(ios::right, ios::adjustfield);
// or cout << showpoint << fixed << right;
    cout << "First format:\n";
    cout << setw(30) << name << ": $" << setprecision(2)
         << setw(10) << hourly << ":" << setprecision(1)
         << setw(5) << hours << "\n";
    cout << "Second format:\n";
    cout.setf(ios::left, ios::adjustfield);
    cout << setw(30) << name << ": $" << setprecision(2)
         << setw(10) << hourly << ":" << setprecision(1)
         << setw(5) << hours << "\n";
    return 0;
}
8:

Consider the following program:

//rq17-8.cpp
#include <iostream>
using namespace std;
int main()
{
    char ch;
    int ct1 = 0;
    cin >> ch;
    while (ch != 'q')
    {
        ct1++;
        cin >> ch;
    }
    int ct2 = 0;
    cin.get(ch);
    while (ch != 'q')
    {
        ct2++;
        cin.get(ch);
    }
    cout << "ct1 = " << ct1 << "; ct2 = " << ct2 << "\n";
    return 0;
}

What does it print, given the following input:

I see a q<Enter>
I see a q<Enter>

Here <Enter> signifies pressing the Enter key.

A:

Here is the output:

ct1 = 5; ct2 = 9

The first part of the program ignores spaces and newlines; the second part doesn't. Note that the second part of the program begins reading at the newline character following the first q, and it counts that newline as part of its total.

9:

Both of the following statements read and discard characters up to and including the end of a line. In what way does the behavior of one differ from that of the other?

while (cin.get() != '\n')
    continue;
cin.ignore(80, '\n');
A:

The ignore() form falters if the input line exceeds 80 characters. In that case it only skips the first 80 characters.

 

CONTENTS