Answers to Self-Test Exercises 577 { cout << ’*’; } else { stars(n - 1); cout << ’*’; } } 3. using std::cout; void backward(int n) { if (n < 10) { cout << n; } else { cout << (n%10);//write last digit backward(n/10);//write the other digits backward } } 4–5. The answer to 4 is writeUp;. The answer to 5 is writeDown;. #include <iostream> using std::cout; using std::endl; void writeDown(int n) { if (n >= 1) { cout << n << " "; //write while the //recursion winds writeDown(n - 1); } } // 5 void writeUp(int n) { if (n >= 1) { writeUp(n - 1); cout << n << " "; //write while the //recursion unwinds 578 Recursion } } //testing code for both Exercises 4 and 5 int main( ) { cout << "calling writeUp(" << 10 << ")\n"; writeUp(10); cout << endl; cout << "calling writeDown(" << 10 << ")\n"; writeDown(10); cout << endl; return 0; } /* Test results calling writeUp(10) 1 2 3 4 5 6 7 8 9 10 calling writeDown(10) 10 9 8 7 6 5 4 3 2 1*/ 6. An error message that says “stack overflow” is telling you that the computer has attempted to place more activation frames on the stack than are allowed on your system. A likely cause of this error message is infinite recursion. 7. using std::cout; void cheers(int n) { while (n > 1) { cout << "Hip "; n ; } cout << "Hurray\n"; } 8. using std::cout; void stars(int n) { for (int count = 1; count <= n; count++) cout << ’*’; } 9. using std::cout; void backward(int n) { while (n >= 10) Answers to Self-Test Exercises 579 { cout << (n%10);//write last digit n = n/10;//discard the last digit } cout << n; } 10. Trace for Self-Test Exercise 4. If n = 3, the code to be executed is if (3 >= 1) { writeDown(3 - 1); } On the next recursion, n = 2 and the code to be executed is if (2 >= 1) { writeDown(2 - 1) } On the next recursion, n = 1 and the code to be executed is if (1 >= 1) { writeDown(1 - 1) } On the final recursion, n = 0 and the true clause is not executed: if (0 >= 1) // condition false { // this clause is skipped } The recursion unwinds, the cout << n << " "; line of code is executed for each recursive call that was on the stack, with n = 3, then n = 2, and finally n = 1. The output is 3 2 1. 11. Trace for Self-Test Exercise 5. If n = 3, the code to be executed is if (3 >= 1) { cout << 3 << " "; writeUp(3 - 1); } On the next recursion, n = 2 and the code to be executed is if (2 >= 1) { cout << 2 << " "; writeUp(2 - 1); 580 Recursion } On the next recursion, n = 1 and the code to be executed is if (1 >= 1) { cout << 1 << " "; writeUp(1 - 1); } On the final recursion, n = 0 and the code to be executed is if (0 >= 1) // condition false, body skipped { // skipped } The recursions unwind; the output (obtained by working through the stack) is 1 2 3. 12. 6 13. The output is 24. The function is the factorial function, usually written n ! and defined as follows: n ! is equal to n *( n - 1)*( n - 2)*. . .*1 14. //Uses iostream and cstdlib: double power(int x, int n) { if (n < 0 && x == 0) { cout << "Illegal argument to power.\n"; exit(1); } if (n < 0) return ( 1/power(x, -n)); else if (n > 0) return ( power(x, n - 1)*x ); else // n == 0 return (1.0); } 15. int squares(int n) { if (n <= 1) return 1; else return ( squares(n - 1) + n*n ); } Programming Projects 581 PROGRAMMING PROJECTS 1. Write a recursive function definition for a function that has one parameter n of type int and that returns the nth Fibonacci number. The Fibonacci numbers are F 0 is 1, F 1 is 1, F 2 is 2, F 3 is 3, F 4 is 5, and in general F i+2 = F i + F i+1 for i = 0, 1, 2, . . . 2. The formula for computing the number of ways of choosing r different things from a set of n things is the following: C ( n , r ) = n !/( r !*( n - r )!) The factorial function n! is defined by n ! = n *( n -1)*( n -2)*. . .*1 Discover a recursive version of the formula for C(n, r) and write a recursive function that computes the value of the formula. Embed the function in a program and test it. 3. Write a recursive function that has an argument that is an array of characters and two argu- ments that are array indexes. The function should reverse the order of those entries in the array whose indexes are between the two bounds. For example, if the array is a[1] == ’A’ a[2] == ’B’ a[3] == ’C’ a[4] == ’D’ a[5] == ’E’ and the bounds are 2 and 5, then after the function is run the array elements should be a[1] == ’A’ a[2] == ’E’ a[3] == ’D’ a[4] == ’C’ a[5] == ’B’ Embed the function in a program and test it. After you have fully debugged this function, define another function that takes a single argument that is an array that contains a string value; the function should reverse the spelling of the string value in the array argument. This function will include a call to the recursive definition you did for the first part of this project. Embed this second function in a program and test it. 4. Write an iterative version of the recursive function in the previous project. Embed it in a program and test it. 5. Towers of Hanoi. There is a story about Buddhist monks who are playing this puzzle with 64 stone disks. The story claims that when the monks finish moving the disks from one post to a second via the third post, time will end. Eschatology (concerns about the end of time) and theology will be left to those better qualified; our interest is limited to the recur- sive solution to the problem. A stack of n disks of decreasing size is placed on one of three posts. The task is to move the disks one at a time from the first post to the second. To do this, any disk can be moved from any post to any other post, subject to the rule that you can never place a larger disk over a smaller disk. The (spare) third post is provided to make the solution possible. Your task is to write a recursive function that describes instructions for a solution to this 582 Recursion problem. We don’t have graphics available, so you should output a sequence of instructions that will solve the problem. Hint: If you could move n-1 of the disks from the first post to the third post using the second post as a spare, the last disk could be moved from the first post to the second post. Then by using the same technique (whatever that may be) you can move the n-1 disks from the third post to the second post, using the first disk as a spare. There! You have the puzzle solved. You only have to decide what the nonrecursive case is, what the recursive case is, and when to output instructions to move the disks. 6. (You need to have first done Programming Project 1.) In this exercise you will compare the efficiency of a recursive and an iterative function to compute the Fibonacci number. a. Examine the recursive function computation of Fibonacci numbers. Note that each Fibonacci number is recomputed many times. To avoid this recomputation, do programming problem 1 iteratively, rather than recursively; that is, do the problem with a loop. You should compute each Fibonacci number once on the way to the number requested and discard the numbers when they are no longer needed. b. Time the solution for project 1 and part a of this project in finding the 1 st , 3 rd , 5 th , 7 th , 9 th , 11 th , 13 th , and 15 th Fibonacci numbers. Determine how long each function takes. Compare and comment on your results. Hints: If you are running Linux, you can use the Bash ‘time’ utility. It gives real time (as in wall clock time), user time (time measured by cpu cycles devoted to your program), and sys time (cpu cycles devoted to tasks other than your program). If you are running in some other environment, you will have to read your manual, or ask your instructor, to find out how to measure the time a program takes to run. 7. (You need to have first done Programming Project 6.) When computing a Fibonacci num- ber using the most straight forward recursive function definition, the recursive solution recomputes each Fibonacci number too many times. To compute F i+2 = F i + F i+1 , it com- putes all the numbers computed in F i a second time in computing F i+1 . You can avoid this by saving the numbers in an array while computing F i . Write another version of your recursive Fibonacci function based on this idea. In the recursive solution for calculating the N th Fibonacci number, declare an array of size N. Array entry with index i stores the i th (i ≤ N) Fibonacci number as it is computed the first time. Then use the array to avoid the second (redundant) recalculation of the Fibonacci numbers. Time this solution as in Pro- gramming Project 6, and compare it to your results for the iterative solution. For additional online Programming Projects, click the CodeMate icons below. 1.7 14 Inheritance 14.1 INHERITANCE BASICS 584 Derived Classes 584 Constructors in Derived Classes 594 Pitfall: Use of Private Member Variables from the Base Class 596 Pitfall: Private Member Functions Are Effectively Not Inherited 598 The protected Qualifier 598 Redefinition of Member Functions 601 Redefining versus Overloading 603 Access to a Redefined Base Function 604 Functions That Are Not Inherited 605 14.2 PROGRAMMING WITH INHERITANCE 606 Assignment Operators and Copy Constructors in Derived Classes 606 Destructors in Derived Classes 607 Example: Partially Filled Array with Backup 608 Pitfall: Same Object on Both Sides of the Assignment Operator 617 Example: Alternate Implementation of PFArrayDBak 617 Tip: A Class Has Access to Private Members of All Objects of the Class 618 Tip: “Is a” versus “Has a” 620 Protected and Private Inheritance 621 Multiple Inheritance 622 CHAPTER SUMMARY 623 ANSWERS TO SELF-TEST EXERCISES 623 PROGRAMMING PROJECTS 625 14 Inheritance Like mother, like daughter Common saying INTRODUCTION Object-oriented programming is a popular and powerful programming tech- nique. Among other things, it provides for a dimension of abstraction known as inheritance. This means that a very general form of a class can be defined and compiled. Later, more specialized versions of that class may be defined and can inherit the properties of the general class. This chapter covers inheritance in general and, more specifically, how it is realized in C++. This chapter does not use any of the material presented in Chapter 12 (file I/O) or Chapter 13 (recursion). It also does not use the material in Section 7.3 of Chapter 7, which covers vectors. Section 14.1 also does not use any mate- rial from Chapter 10 (pointers and dynamic arrays). Inheritance Basics If there is anything that we wish to change in the child, we should first examine it and see whether it is not something that could better be changed in ourselves. Carl Gustav Jung, The Integration of the Personality Inheritance is the process by which a new class—known as a derived class —is created from another class, called the base class . A derived class automatically has all the member variables and all the ordinary member functions that the base class has, and can have additional member functions and additional member variables. ■ DERIVED CLASSES Suppose we are designing a record-keeping program that has records for salaried employees and hourly employees. There is a natural hierarchy for grouping these classes. These are all classes of people who share the property of being employees. Employees who are paid an hourly wage are one subset of employees. Another subset consists of employees who are paid a fixed wage each month or week. Although the program may not need any type corresponding to the set of all employees, thinking in terms of the more general concept of employees 14.1 derived class base class Inheritance Basics 585 can be useful. For example, all employees have names and Social Security numbers, and the member functions for setting and changing names and Social Security numbers will be the same for salaried and hourly employees. Within C++ you can define a class called Employee that includes all employees, whether salaried or hourly, and then use this class to define classes for hourly employees and salaried employees. The class Employee will also contain member functions that manipulate the data fields of the class Employee . Displays 14.1 and 14.2 show one possible definition for the class Employee . Display 14.1 Interface for the Base Class Employee 1 2 //This is the header file employee.h. 3 //This is the interface for the class Employee. 4 //This is primarily intended to be used as a base class to derive 5 //classes for different kinds of employees. 6 #ifndef EMPLOYEE_H 7 #define EMPLOYEE_H 8 #include <string> 9 using std::string; 10 namespace SavitchEmployees 11 { 12 class Employee 13 { 14 public: 15 Employee( ); 16 Employee(string theName, string theSsn); 17 string getName( ) const; 18 string getSsn( ) const; 19 double getNetPay( ) const; 20 void setName(string newName); 21 void setSsn(string newSsn); 22 void setNetPay(double newNetPay); 23 void printCheck( ) const; 24 private: 25 string name; 26 string ssn; 27 double netPay; 28 }; 29 }//SavitchEmployees 30 #endif //EMPLOYEE_H 586 Inheritance Display 14.2 Implementation for the Base Class Employee (part 1 of 2) 1 2 //This is the file employee.cpp. 3 //This is the implementation for the class Employee. 4 //The interface for the class Employee is in the header file employee.h. 5 #include <string> 6 #include <cstdlib> 7 #include <iostream> 8 #include "employee.h" 9 using std::string; 10 using std::cout; 11 namespace SavitchEmployees 12 { 13 Employee::Employee( ) : name("No name yet"), ssn("No number yet"), netPay(0) 14 { 15 //deliberately empty 16 } 17 Employee::Employee(string theName, string theNumber) 18 : name(theName), ssn(theNumber), netPay(0) 19 { 20 //deliberately empty 21 } 22 string Employee::getName( ) const 23 { 24 return name; 25 } 26 string Employee::getSsn( ) const 27 { 28 return ssn; 29 } 30 31 double Employee::getNetPay( ) const 32 { 33 return netPay; 34 } 35 void Employee::setName(string newName) 36 { 37 name = newName; 38 } 39 void Employee::setSsn(string newSsn) . Projects, click the CodeMate icons below. 1.7 14 Inheritance 14.1 INHERITANCE BASICS 584 Derived Classes 584 Constructors in Derived Classes 594 Pitfall: Use of Private Member Variables from. netPay; 28 }; 29 }//SavitchEmployees 30 #endif //EMPLOYEE_H 586 Inheritance Display 14.2 Implementation for the Base Class Employee (part 1 of 2) 1 2 //This is the file employee.cpp. 3 //This. array argument. This function will include a call to the recursive definition you did for the first part of this project. Embed this second function in a program and test it. 4. Write an iterative