More Tools 283 Display 7.4 The const Parameter Modifier (part 2 of 3) 40 int dollarsPart(double amount) const; 41 int centsPart(double amount) const; 42 int round(double number) const; 43 double fraction(double percent) const; 44 //Converts a percentage to a fraction. For example, fraction(50.3) returns 0.503. 45 }; 46 //Returns true if the balance in account1 is greater than that 47 //in account2. Otherwise returns false. 48 bool isLarger(const BankAccount& account1, const BankAccount& account2); 49 void welcome(const BankAccount& yourAccount); 50 int main( ) 51 { 52 BankAccount account1(6543.21, 4.5), account2; 53 welcome(account1); 54 cout << "Enter data for account 2:\n"; 55 account2.input( ); 56 if (isLarger(account1, account2)) 57 cout << "account1 is larger.\n"; 58 else 59 cout << "account2 is at least as large as account1.\n"; 60 return 0; 61 } 62 63 bool isLarger(const BankAccount& account1, const BankAccount& account2) 64 { 65 return(account1.getBalance( ) > account2.getBalance( )); 66 } 67 void welcome(const BankAccount& yourAccount) 68 { 69 cout << "Welcome to our bank.\n" 70 << "The status of your account is:\n"; 71 yourAccount.output( ); 72 } 73 //Uses iostream and cstdlib: 74 void BankAccount::output( ) const 75 < The rest of the function definition is the same as in Display 7.2. > 76 < Other function definitions are the same as in Display 7.2, except that 77 const is added where needed to match the function declaration. > 07_CH07.fm Page 283 Wednesday, August 13, 2003 12:58 PM 284 Constructors and Other Tools Self-Test Exercises ■ INLINE FUNCTIONS You can give the complete definition of a member function within the definition of its class. Such definitions are called inline function definitions. These inline definitions are typically used for very short function definitions. Display 7.5 shows the class in Display 7.4 rewritten with a number of inline functions. Inline functions are more than just a notational variant of the kind of member func- tion definitions we have already seen. The compiler treats an inline function in a special way. The code for an inline function declaration is inserted at each location where the function is invoked. This saves the overhead of a function invocation. All other things being equal, an inline function should be more efficient and hence presumably preferable to a function defined in the usual way. However, all other things are seldom, if ever, equal. Inline functions have the disadvantage of mixing the interface and implementation of a class and so go against the principle of encapsulation. And, so the usual arguments go back and forth. It is generally believed that only very short function definitions should be defined inline. For long function definitions, the inline version can actually be less efficient, because a large piece of code is repeated frequently. Beyond that general rule, you will have to decide for yourself whether to use inline functions. Any function can be defined to be an inline function. To define a nonmember func- tion to be inline, just place the keyword inline before the function declaration and function definition. We will not use, or further discuss, inline nonmember functions in this book. 7. Rewrite the definition of the class DayOfYear given in Display 7.3 so that the functions getMonthNumber and getDay are defined inline. Display 7.4 The const Parameter Modifier (part 3 of 3) S AMPLE D IALOGUE Welcome to our bank. The status of your account is: Account balance: $6543.21 Rate: 4.5% Enter data for account 2: Enter account balance $100.00 Enter interest rate (NO percent sign): 10 account1 is larger. inline function 07_CH07.fm Page 284 Wednesday, August 13, 2003 12:58 PM More Tools 285 Display 7.5 Inline Function Definitions 1 #include <iostream> 2 #include <cmath> 3 #include <cstdlib> 4 using namespace std; 5 class BankAccount 6 { 7 public: 8 BankAccount(double balance, double rate); 9 BankAccount(int dollars, int cents, double rate); 10 BankAccount(int dollars, double rate); 11 BankAccount( ); 12 void update( ); 13 void input( ); 14 void output( ) const; 15 double getBalance( ) const { return (accountDollars + accountCents*0.01);} 16 int getDollars( ) const { return accountDollars; } 17 int getCents( ) const { return accountCents; } 18 double getRate( ) const { return rate; } 19 void setBalance(double balance); 20 void setBalance(int dollars, int cents); 21 void setRate(double newRate); 22 private: 23 int accountDollars; //of balance 24 int accountCents; //of balance 25 double rate;//as a percentage 26 int dollarsPart(double amount) const { return static_cast<int>(amount); } 27 int centsPart(double amount) const; 28 int round(double number) const 29 { return static_cast<int>(floor(number + 0.5)); } 30 double fraction(double percent) const { return (percent/100.0); } 31 }; < Inline functions have no further definitions. Other function definitions are as in Display 7.4. > This is Display 7.4 rewritten using inline member functions. 07_CH07.fm Page 285 Wednesday, August 13, 2003 12:58 PM 286 Constructors and Other Tools ■ STATIC MEMBERS Sometimes you want to have one variable that is shared by all the objects of a class. For example, you might want one variable to count the number of times a particular mem- ber function is invoked by all objects of the class. Such variables are called static vari- ables and can be used for objects of the class to communicate with each other or coordinate their actions. Such variables allow some of the advantages of global variables without opening the flood gates to all the abuses that true global variables invite. In particular, a static variable can be private so that only objects of the class can directly access it. If a function does not access the data of any object and yet you want the function to be a member of the class, you can make it a static function. Static functions can be invoked in the normal way, using a calling object of the class. However, it is more com- mon and clearer to invoke a static function using the class name and scope resolution operator, as in the following example: Server::getTurn( ) Because a static function does not need a calling object, the definition of a static function cannot use anything that depends on a calling object. A static function defini- tion cannot use any nonstatic variables or nonstatic member functions, unless the non- static variable or function has a calling object that is a local variable or some object otherwise created in the definition. If that last sentence seems hard to understand, just use the simpler rule that the definition of a static function cannot use anything that depends on a calling object. Display 7.6 is a demonstration program that uses both static variables and static functions. Note that static variables are indicated by the qualifying keyword static at the start of their declaration. Also notice that all the static variables are initialized as follows: int Server::turn = 0; int Server::lastServed = 0; bool Server::nowOpen = true; Such initialization requires a bit of explanation. Every static variable must be initialized outside the class definition. Also, a static variable cannot be initialized more than once. As in Display 7.6, private static variables—in fact, all static variables—are initialized outside the class. This may seem to be contrary to the notion of private. However, the author of a class is expected to do the initializations, typically in the same file as the class definition. In that case, no programmer who uses the class can initialize the static variables, since a static variable cannot be initialized a second time. Notice that the keyword static is used in the member function declaration but is not used in the member function definition. static variable initializing static member variables 07_CH07.fm Page 286 Wednesday, August 13, 2003 12:58 PM More Tools 287 Display 7.6 Static Members (part 1 of 2) 1 #include <iostream> 2 using namespace std; 3 class Server 4 { 5 public: 6 Server(char letterName); 7 static int getTurn( ); 8 void serveOne( ); 9 static bool stillOpen( ); 10 private: 11 static int turn; 12 static int lastServed; 13 static bool nowOpen; 14 char name; 15 }; 16 int Server:: turn = 0; 17 int Server:: lastServed = 0; 18 bool Server::nowOpen = true; 19 int main( ) 20 { 21 Server s1(’A’), s2(’B’); 22 int number, count; 23 do 24 { 25 cout << "How many in your group? "; 26 cin >> number; 27 cout << "Your turns are: "; 28 for (count = 0; count < number; count++) 29 cout << Server::getTurn( ) << ' '; 30 cout << endl; 31 s1.serveOne( ); 32 s2.serveOne( ); 33 } while (Server::stillOpen( )); 34 cout << "Now closing service.\n"; 35 return 0; 36 } 37 38 Server::Server(char letterName) : name(letterName) 39 {/*Intentionally empty*/} 40 int Server::getTurn( ) 41 { 42 turn++; 43 return turn; 44 } Since getTurn is static, only static members can be referenced in here. 07_CH07.fm Page 287 Wednesday, August 13, 2003 12:58 PM 288 Constructors and Other Tools The program in Display 7.6 is the outline of a scenario that has one queue of clients waiting for service and two servers to service this single queue. You can come up with a number of system programming scenarios to flesh this out to a realistic example. For a simple minded model just to learn the concepts, think of the numbers produced by getTurn as those little slips of paper handed out to customers in a delicatessen or ice cream shop. The two servers are then two clerks who wait on customers. One perhaps peculiar detail of this shop is that customers arrive in groups but are waited on one at a time (perhaps to order their own particular kind of sandwich or ice cream flavor). Display 7.6 Static Members (part 2 of 2) 45 bool Server::stillOpen( ) 46 { 47 return nowOpen; 48 } 49 void Server::serveOne( ) 50 { 51 if (nowOpen && lastServed < turn) 52 { 53 lastServed++; 54 cout << "Server " << name 55 << " now serving " << lastServed << endl; 56 } 57 if (lastServed >= turn) //Everyone served 58 nowOpen = false; 59 } S AMPLE D IALOGUE How many in your group? 3 Your turns are: 1 2 3 Server A now serving 1 Server B now serving 2 How many in your group? 2 Your turns are: 4 5 Server A now serving 3 Server B now serving 4 How many in your group? 0 Your turns are: Server A now serving 5 Now closing service. 07_CH07.fm Page 288 Wednesday, August 13, 2003 12:58 PM More Tools 289 Self-Test Exercises 8. Could the function defined as follows be added to the class Server in Display 7.6 as a static function? Explain your answer. void Server::showStatus( ) { cout << "Currently serving " << turn << endl; cout << "server name " << name << endl; } ■ NESTED AND LOCAL CLASS DEFINITIONS The material in this section is included for reference value and, except for a brief pass- ing reference in Chapter 17, is not used elsewhere in this book. You can define a class within a class. Such a class within a class is called a nested class. The general layout is obvious: class OuterClass { public: private: class InnerClass { }; }; A nested class can be either public or private. If it is private, as in our sample layout, then it cannot be used outside of the outer class. Whether the nested class is public or private, it can be used in member function definitions of the outer class. Since the nested class is in the scope of the outer class, the name of the nested class, like InnerClass in our sample layout, may be used for something else outside of the outer class. If the nested class is public, the nested class can be used as a type outside of the outer class. However, outside of the outer class, the type name of the nested class is OuterClass::InnerClass. We will not have occasion to use such nested class definitions in this book. However, in Chapter 17 we do suggest one possible application for nested classes. 2 A class definition can also be defined within a function definition. In such cases the class is called a local class, since its meaning is confined to the function definition. A 2 The suggestion is in the subsection of Chapter 17 entitled “Friend Classes and Similar Alter- natives.” nested class local class 07_CH07.fm Page 289 Wednesday, August 13, 2003 12:58 PM 290 Constructors and Other Tools local class may not contain static members. We will not have occasion to use local classes in this book. Vectors—A Preview of the Standard Template Library “Well, I’ll eat it,” said Alice, “and if it makes me grow larger, I can reach the key; and if it makes me grow smaller, I can creep under the door; so either way I’ll get into the garden.” Lewis Carroll, Alice’s Adventures in Wonderland Vectors can be thought of as arrays that can grow (and shrink) in length while your program is running. In C++, once your program creates an array, it cannot change the length of the array. Vectors serve the same purpose as arrays except that they can change length while the program is running. Vectors are formed from a template class in the Standard Template Library (STL). We discuss templates in Chapter 16 and discuss the STL in Chapter 19. However, it is easy to learn some basic uses of vectors before you learn about templates and the STL in detail. You do not need to know a great deal about classes to use vectors. You can cover this section on vectors after reading Chapter 6. You need not have read the previ- ous sections of this chapter before covering this section. ■ VECTOR BASICS Like an array, a vector has a base type, and like an array, a vector stores a collection of values of its base type. However, the syntax for a vector type and a vector variable decla- ration is different from the syntax for arrays. You declare a variable, v, for a vector with base type int as follows: vector<int> v; The notation vector< Base_Type > is a template class, which means you can plug in any type for Base_Type and that will produce a class for vectors with that base type. You can simply think of this as specifying the base type for a vector in the same sense as you specify a base type for an array. You can use any type, including class types, as the base type for a vector. The notation vector<int> is a class name and so the previous declara- tion of v as a vector of type vector<int> includes a call to the default constructor for the class vector<int> that creates a vector object that is empty (has no elements). Vector elements are indexed starting with 0, the same as arrays. The square brackets notation can be used to read or change these elements, just as with an array. For exam- ple, the following changes the value of the ith element of the vector v and then outputs that changed value. ( i is an int variable.) 7.3 vector declaring a vector variable template class v[i] 07_CH07.fm Page 290 Wednesday, August 13, 2003 12:58 PM Vectors—A Preview of the Standard Template Library 291 v[i] = 42; cout << "The answer is " << v[i]; There is, however, a restriction on this use of the square brackets notation with vectors that is unlike the same notation used with arrays. You can use v[i] to change the value of the ith element. However, you cannot initialize the ith element using v[i]; you can only change an element that has already been given some value. To add an element to a vector for the first time, you normally use the member function push_back. You add elements to a vector in order of positions, first at position 0, then position 1, then 2, and so forth. The member function push_back adds an element in the next available position. For example, the following gives initial values to elements 0, 1, and 2 of the vector sample: vector<double> sample; sample.push_back(0.0); sample.push_back(1.1); sample.push_back(2.2); The number of elements in a vector is called the size of the vector. The member function size can be used to determine how many elements are in a vector. For exam- ple, after the previously shown code is executed, sample.size( ) returns 3. You can write out all the elements currently in the vector sample as follows: for (int i = 0; i < sample.size( ); i++) cout << sample[i] << endl; The function size returns a value of type unsigned int, not a value of type int. This returned value should be automatically converted to type int when it needs to be of type int, but some compiler may warn you that you are using an unsigned int where an int is required. If you want to be very safe, you can always apply a type cast to convert the returned unsigned int to an int, or in cases like this for loop, use a loop control variable of type unsigned int as follows: for (unsigned int i = 0; i < sample.size( ); i++) cout << sample[i] << endl; A simple demonstration illustrating some basic vector techniques is given in Display 7.7. There is a vector constructor that takes one integer argument and will initialize the number of positions given as the argument. For example, if you declare v as follows: vector<int> v(10); then the first ten elements are initialized to 0 and v.size( ) would return 10. You can then set the value of the ith element using v[i] for values of i equal to 0 through 9. In particular, the following could immediately follow the declaration: for (unsigned int i = 0; i < 10; i++) v[i] = i; push_back size size unsigned int 07_CH07.fm Page 291 Wednesday, August 13, 2003 12:58 PM 292 Constructors and Other Tools To set the ith element for i greater than or equal to 10, you would use push_back. When you use the constructor with an integer argument, vectors of numbers are ini- tialized to the zero of the number type. If the vector base type is a class type, the default constructor is used for initialization. Display 7.7 Using a Vector 1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 int main( ) 5 { 6 vector<int> v; 7 cout << "Enter a list of positive numbers.\n" 8 << "Place a negative number at the end.\n"; 9 int next; 10 cin >> next; 11 while (next > 0) 12 { 13 v.push_back(next); 14 cout << next << " added. "; 15 cout << "v.size( ) = " << v.size( ) << endl; 16 cin >> next; 17 } 18 cout << "You entered:\n"; 19 for (unsigned int i = 0; i < v.size( ); i++) 20 cout << v[i] << " "; 21 cout << endl; 22 return 0; 23 } S AMPLE D IALOGUE Enter a list of positive numbers. Place a negative number at the end. 2 4 6 8 -1 2 added. v.size = 1 4 added. v.size = 2 6 added. v.size = 3 8 added. v.size = 4 You entered: 2 4 6 8 07_CH07.fm Page 292 Wednesday, August 13, 2003 12:58 PM . More Tools 283 Display 7.4 The const Parameter Modifier (part 2 of 3) 40 int dollarsPart(double amount) const; 41 int centsPart(double amount) const; 42 int round(double number) const; 43. percentage 26 int dollarsPart(double amount) const { return static_cast<int>(amount); } 27 int centsPart(double amount) const; 28 int round(double number) const 29 { return static_cast<int>(floor(number. are waited on one at a time (perhaps to order their own particular kind of sandwich or ice cream flavor). Display 7.6 Static Members (part 2 of 2) 45 bool Server::stillOpen( ) 46 { 47 return