Sei sulla pagina 1di 44

Bonus Chapter 1

A Functional Budget Program


In This Chapter
Manipulating pointers to objects Implementing polymorphism to reduce duplication of code Demonstrating the strong typing made possible by templatized classes Using a list template from the Standard Template Library

his bonus chapter walks you through a series of programs related to a fictional bank account. The first program, BUDGET1, solves the bank account problem using simplistic and error-prone functional programming techniques. BUDGET2 cleans things up by bundling account information into one of two classes, Savings or Checking. BUDGET3 expresses the relationship between Savings and Checking by extending them from a common Account class. BUDGET3 also stores its objects in a linked list. BUDGET4 generalizes the linked list by turning it into the template class LinkedList<class T>, and BUDGET5 uses one of the Standard Template Library containers instead of reinventing the wheel.

BUDGET1
The chapters that make up Parts I and II provide you the programming information necessary to write your own non-trivial programs. The following program, BUDGET1, is just such a program. This program uses the C++ concepts presented in Parts I and II of the book. The BUDGET program is a simple bank account register program. Heres what it does: Gives the user the ability to create one or more bank accounts. Assigns an account number to each account.

BC2

C++ For Dummies, 5th Edition


Begins accepting transactions, consisting of deposits and withdrawals. After the user chooses to exit, the program displays the ending balance of all accounts and the total of all accounts. This program mimics a few bank rules concerning transactions (you will add more rules as the program develops): Never let the balance become negative. (Your bank may be friendly, but I bet its not that friendly.) Never charge for making a deposit. The following budget program is explained below:
// BUDGET1.CPP - A functional BUDGET program; // this program accepts deposits and // withdrawals on some number of accounts; // eventually it displays the accounts // created #include <cstdio> #include <cstdlib> #include <iostream> using namespace std; // the maximum number of accounts you can have const int maxAccounts = 10; // data describes accounts unsigned accountNumber[maxAccounts]; double balance[maxAccounts]; // prototype declarations void process(unsigned& accountNumber, double& balance); void init(unsigned* pAccountNumber, double* pBalance); // main - accumulate the initial input and output totals int main(int nNumberofArgs, char* pszArgs[]) { cout << Enter C to continue or X to terminate:; // loop until someone enters int noAccounts = 0; // the number of accounts // dont create more accounts than we have room for cout << This program creates bank accounts\n << endl; while (noAccounts < maxAccounts) { char transactionType; cout << Enter C to create another account << or X to terminate:; cin >> transactionType;

Bonus Chapter 1: A Functional Budget Program


// quit if the user enters an X; otherwise... if (transactionType == x || transactionType == X) { break; } // if the user enters a C then... if (transactionType == c || transactionType == C) { // initialize a new account... // (pass address so that function can change // the value for us) init(&accountNumber[noAccounts], &balance[noAccounts]); // input transaction information process(accountNumber[noAccounts], balance[noAccounts]); // move the index over to the next account noAccounts++; } } // now present totals // first for each account double total = 0; cout << Account information:\n; for (int i = 0; i < noAccounts; i++) { cout << Balance for account << accountNumber[i] << = << balance[i] << \n; // accumulate the total for all accounts total += balance[i]; } // now display the accumulated value cout << Balance for all accounts = << total << \n; // wait until user is ready before terminating program // to allow the user to see the program results system(PAUSE); return 0; }

BC3

BC4

C++ For Dummies, 5th Edition


// init - initialize an account by reading // in the account number and zeroing out the // balance (use pointers now) void init(unsigned* pAccountNumber, double* pBalance) { cout << Enter account number:; cin >> *pAccountNumber; *pBalance = 0.0; } // process - update the account balance by entering // the transactions from the user // (use a reference argument for this example // the effect is the same as using a pointer) void process(unsigned& accountNumber, double& balance) { cout << Enter positive number for deposit,\n << negative for withdrawal,\n << or zero to terminate << endl; double transaction; do { cout << :; cin >> transaction; // if its a deposit... if (transaction > 0) { // ...add it to the balance balance += transaction; } // how about withdrawal? if (transaction < 0) { // withdrawal - its easier // to think of a withdrawal as a positive number transaction = -transaction; if (balance < transaction) { cout << Insufficient funds: balance << balance << , check << transaction << \n;

Bonus Chapter 1: A Functional Budget Program


} else { balance -= transaction; } } } while (transaction != 0); }

BC5

To demonstrate the program in action, I entered the following sequence:


Enter C to continue or X to terminate:This program creates bank accounts Enter C to create another account or X Enter account number:1234 Enter positive number for deposit, negative for withdrawal, or zero to terminate :200 :-100 :-200 Insufficient funds: balance 100, check :0 Enter C to create another account or X Enter account number:2345 Enter positive number for deposit, negative for withdrawal, or zero to terminate :200 :-50 :-50 :0 Enter C to create another account or X Account information: Balance for account 1234 = 100 Balance for account 2345 = 100 Balance for all accounts = 200 Press any key to continue . . . to terminate:C

200 to terminate:c

to terminate:x

Heres how the BUDGET1.C program works. Two arrays are created, one to contain account numbers and the other their balances. These two arrays are kept in synch; that is, balance[n] contains the balance of the account accountNumber[n] no matter what the value of n. Due to the limitations of a fixed-length array, the program can accommodate only MAXACCOUNTS number of bank accounts. The main program is divided into two sections: the accumulation section, where the deposits and withdrawals are accumulated into accounts; and the display section. The accumulation section first enters a loop in which the

BC6

C++ For Dummies, 5th Edition


accounts are handled separately. First, the program prompts the user for a C for continue or an X for exit. If the user enters an X, the program breaks from the loop and enters the second section of main(). The program exits the loop after MAXACCOUNTS number of accounts have been created, whether the user enters an X or not. Notice that the program checks for both X and x. Although C++ considers case to be important, people generally dont. If the user enters C, control passes to the init() function, which enters the account number information (creates an account) followed by the process() function, which enters the transaction data into the account. The program passes the address of the account number and the balance to init(). This allows init() to modify these values back in the main program. The arguments to process() have been declared referential for the same reason. I did this to contrast the pointer style with the referential style of argument passing. See Chapter 6 for a discussion of function arguments.

Coding styles
You may notice that I try to be consistent in my indentation and in my naming of variables. We humans have a limited amount of CPU power between our ears. We need to direct our CPU power toward getting programs working, not toward figuring out simple stuff like indentation. This makes it important that you be consistent in how you name variables, where you place open and close braces, and so on. This is called your coding style. When you have developed a style, stick to it after a while, your coding style will become second nature. Youll find that you can code your programs in less time and read your programs with less effort. When working on a project with several programmers, its just as important that you all use the same style to avoid a Tower of Babel effect with conflicting and confusing formats. The programmer editor can help here both Visual C++ and Dev-C++ allow you to set up certain programming style parameters such as the number of spaces to indent, whether the braces are lined up with the for statement or are indented as well, and so on. In addition, I strongly suggest that you enable every error and warning message that your compiler can produce. Even if you decide that a particular warning is not a problem, why would you want it suppressed? You can always ignore it. More often than not, even a warning represents a potential problem or programming style that needs to be corrected. Some people dont like the compiler finding their slip-ups because they think its embarrassing and they think that correcting things to get rid of the warnings wastes time. Just think how embarrassing and time-consuming it is to painstakingly search for a bug only to find that its a problem your compiler told you about hours ago.

Bonus Chapter 1: A Functional Budget Program


After the program exits the account creation section, it enters the output second. Here, main() cycles through each account, outputting the balance in each. The program ends with the total balance of all accounts. The init() function creates a new account by prompting the user, inputting the account number, and zeroing out the balance. Always create an element in a legal state. An initial balance of 0 makes sense an initial balance containing random garbage does not. The process() function enters a loop inputting transaction information. Positive values are taken to be deposits, whereas negative values are taken as withdrawals. An entry of 0 is assumed to be the last transaction for a given account. The program is using an otherwise nonsensical value as a flag. This technique is common, but not generally a good idea. I use the technique here only because it minimizes the size of the program. Although other (even better) ways exist to implement this program, BUDGET1 serves nicely as the basis for your investigations. As you progress in your knowledge of C++, you will see this program morph into a full-blown, objectoriented C++ program.

BC7

BUDGET2
The BUDGET2 program converts the function-based BUDGET1 solution to an object-based solution based on active classes. Youll need to be familiar with the concepts I present through Part III to understand BUDGET2. The budget problem is to set up accounts like those you see in a bank. These simple accounts provide for deposits (thats good) and withdrawals (thats even better). (The earlier version of BUDGET introduced at the end of Part II of the book handle only a single type of bank account.) This version handles two types of accounts each with its own, slightly different rules. Checking accounts: Charge a fee of 20 cents per check if the balance drops below $500. Do not charge a fee when the balance is above $500.

BC8

C++ For Dummies, 5th Edition


Savings accounts: Do not charge a fee for the first withdrawal of the month. Charge a fee of $5 for each withdrawal thereafter. Looking at the BUDGET problem, its easy to see that the class candidates are
Checking and Savings. You know that its a good idea to make data mem-

bers protected, so a few access functions are necessary in case a nonmember function needs the account number or balance. Like all classes, Checking and Savings need a constructor to initialize objects to legal values (mostly to a balance of 0). Two additional member functions are also necessary: deposit() and withdrawal(). Finally, I added one other member function called display() to display the current object. This is not a requirement, but it is common to let the object display itself rather than rely on an external function to do so. (Those other functions would need knowledge of the classs internals in order to know how to display it properly, and thats something you want to avoid.) Here is the resulting program:
// // BUDGET2.CPP - BUDGET program with active Savings and // Checking classes. // #include <cstdio> #include <cstdlib> #include <iostream> using namespace std; // the maximum number of accounts one can have const int MAXACCOUNTS = 10; // Checking - this describes checking accounts class Checking { public: Checking(int initializeAN = 0) : accountNumber(initializeAN), balance(0.0) {} // access functions int accountNo() { return accountNumber; } double acntBalance() { return balance; } // transaction functions void deposit(double amount) { balance += amount;

Bonus Chapter 1: A Functional Budget Program


} void withdrawal(double amount); // display function for displaying self on cout void display() { cout << Account << accountNumber << = << balance << endl; } protected: unsigned accountNumber; double balance; }; // // withdrawal - this member function is too big to // be defined inline void Checking::withdrawal(double amount) { if (balance < amount) { cout << Insufficient funds: balance << balance << , check << amount << endl; } else { balance -= amount; // if balance falls too low,... if (balance < 500.00) { // ...charge a service fee balance -= 0.20; } } } // Savings - you can probably figure this one out class Savings { public: Savings(int initialAN = 0) : accountNumber(initialAN), balance(0.0), noWithdrawals(0) {} // access functions int accountNo() { return accountNumber; } double acntBalance() { return balance; }

BC9

BC10

C++ For Dummies, 5th Edition


// transaction functions void deposit(double amount) { balance += amount; } void withdrawal(double amount); // display function - display self to cout void display() { cout << Account << accountNumber << = << balance << (no. withdrawals = << noWithdrawals << ) << endl; } protected: unsigned accountNumber; double balance; int noWithdrawals; }; void Savings::withdrawal(double amount) { if (balance < amount) { cout << Insufficient funds: balance << balance << , withdrawal << amount << endl; } else { // after more than one withdrawal in a month... if (++noWithdrawals > 1) { // ...charge a $5 fee balance -= 5.00; } // now make the withdrawal balance -= amount; } } // prototype declarations void process(Checking* pChecking); void process(Savings* pSavings); // checking and savings account objects Checking* chkAcnts[MAXACCOUNTS]; Savings* svgAcnts[MAXACCOUNTS];

Bonus Chapter 1: A Functional Budget Program


// main - accumulate the initial input and output totals int main(int argcs, char* pArgs[]) { // loop until someone enters an X or x int noChkAccounts = 0; // count the number of accounts int noSvgAccounts = 0; char accountType; // S or C while(true) { cout << Enter S for Savings, << C for Checking, << X for exit:; cin >> accountType; // exit the loop when the user enters an X if (accountType == x || accountType == X) { break; } // otherwise, handle according to the account type switch (accountType) { // checking account case c: case C: if (noChkAccounts < MAXACCOUNTS) { int acnt; cout << Enter account number:; cin >> acnt; chkAcnts[noChkAccounts] = new Checking(acnt); process(chkAcnts[noChkAccounts]); noChkAccounts++; } else { cout << No more room for checking accounts << endl; } break; // savings account case s: case S: if (noSvgAccounts < MAXACCOUNTS) { int acnt; cout << Enter account number:;

BC11

BC12

C++ For Dummies, 5th Edition


cin >> acnt; svgAcnts[noSvgAccounts] = new Savings(acnt); process(svgAcnts[noSvgAccounts]); noSvgAccounts++; } else { cout << No more room for savings accounts << endl; } break; default: cout << I didnt get that. << endl; } } // now present totals double chkTotal = 0; // total of all checking accounts cout << Checking accounts:\n; for (int i = 0; i < noChkAccounts; i++) { chkAcnts[i]->display(); chkTotal += chkAcnts[i]->acntBalance(); } double svgTotal = 0; // total of all savings accounts cout << Savings accounts:\n; for (int j = 0; j < noSvgAccounts; j++) { svgAcnts[j]->display(); svgTotal += svgAcnts[j]->acntBalance(); } double total = chkTotal + svgTotal; cout << Total for checking accounts = << chkTotal << endl; cout << Total for savings accounts = << svgTotal << endl; cout << Total worth << total << endl; =

// wait until user is ready before terminating program // to allow the user to see the program results system(PAUSE); return 0; }

Bonus Chapter 1: A Functional Budget Program


// process(Checking) - input the data for a checking account void process(Checking* pChecking) { cout << Enter positive number for deposit,\n << negative for check, 0 to terminate << endl; double transaction; do { cout << :; cin >> transaction; // deposit if (transaction > 0) { pChecking->deposit(transaction); } // withdrawal if (transaction < 0) { pChecking->withdrawal(-transaction); } } while (transaction != 0); } // process(Savings) - input the data for a savings account void process(Savings* pSavings) { cout << Enter positive number for deposit,\n << negative for withdrawal, 0 to terminate << endl; double transaction; do { cout << :; cin >> transaction; // deposit if (transaction > 0) { pSavings->deposit(transaction); } // withdrawal if (transaction < 0) { pSavings->withdrawal(-transaction); } } while (transaction != 0); }

BC13

BC14

C++ For Dummies, 5th Edition


I executed the program with the following data in order to demonstrate how the program works (or, as is so often the case with my programs, doesnt work). Bold characters indicate user input, and non-bold characters indicate output from the program.
Enter S for Savings, C for Checking, X for Enter account number:123 Enter positive number for deposit, negative for withdrawal, 0 to terminate :200 :-20 :0 Enter S for Savings, C for Checking, X for Enter account number:234 Enter positive number for deposit, negative for withdrawal, 0 to terminate :200 :-10 :-10 :0 Enter S for Savings, C for Checking, X for Enter account number:345 Enter positive number for deposit, negative for check, 0 to terminate :200 :-20 :0 Enter S for Savings, C for Checking, X for Enter account number:456 Enter positive number for deposit, negative for check, 0 to terminate :600 :-20 :0 Enter S for Savings, C for Checking, X for Checking accounts: Account 345 = 179.8 Account 456 = 580 Savings accounts: Account 123 = 180 (no. withdrawals = 1) Account 234 = 175 (no. withdrawals = 2) Total for checking accounts = 759.8 Total for savings accounts = 355 Total worth = 1114.8 Press any key to continue . . . exit:S

exit:s

exit:c

exit:C

exit:x

Starting with class Checking, you can see each of the member functions mentioned earlier. The constructor assigns the account number. The = 0 allows the program to construct an object with a default account number of 0:

Bonus Chapter 1: A Functional Budget Program


Checking c1 = new Checking(124); Checking c2 = new Checking();

BC15

In this case, the Checking object c1 is created with account number 123, and the object c2 is created with the default account number of 0. The functions accountNo() and acntBalance() give the outside world access to the protected members accountNumber and balance. The point of such a function is to allow non-class functions to read these values but not modify them. In addition, these access functions will shield outside functions from any future changes in the way that the account number or the balance is stored. The deposit() and withdrawal() functions either deposit or withdraw an amount. Because the deposit() function is simple, it is defined directly inline within the class. The withdrawal() function, being a bit more complicated, is declared here but defined later. The display() function outputs the important data members to the standard output. Notice that providing a function with a display() method is a common (and good) programming practice. The class Savings is virtually identical to the class Checking except for the addition of the member noWithdrawals, which is used to track the number of withdrawals made. Room for the savings account and checking account objects is allocated in the arrays svgAcnts and chkAcnts, respectively. The maximum number of accounts is MAXACCOUNTS. The main() function is slightly more complicated than its BUDGET1 cousin because it must deal with two different types of accounts. After the check for X, main() uses the switch construct to decide between C checking and S savings accounts. The switch construct is used here because it is easier to extend by adding more cases, and because it provides a default case to handle erroneous input. Just as before, the second section of main() actually displays the account data accumulated in the initial section. Notice how the internals of the Checking and Savings objects are hidden from main(). For example, main() asks the objects to display themselves (meaning display the internal components) main() has no idea how the classes choose to do this, nor does it care.

BC16

C++ For Dummies, 5th Edition


The process( ) function that handles the actual deposits and withdrawals relies on the deposit( ) and withdrawal( ) member functions to do the dirty work. Although you know how these actions are performed, remember that process() does not again, nor does it care. However, how a savings account may choose to withdraw cash is up to the class. I encourage you to type this program and single-step through it. Nothing else will give you a feel for whats going on faster than seeing the program in action. Believe it or not, from a programming standpoint, BUDGET2 is actually easier to program than BUDGET1. When writing Savings, I didnt have to worry about how the main program might use the class. The same applied to Checking. In addition, while working on the main functions, I didnt concern myself with class internals. Render unto the class that which is the classs, or something like that. On the negative side, it is clear that there are a lot of similarities between the Savings and Account classes. Somehow, there should be a way to reduce the duplications. In fact, this is exactly the topic of Part IV in the book.

BUDGET3
BUDGET3 continues the metamorphosis of the purely functional BUDGET1 through the object-based version BUDGET2 into an object-oriented program. This program uses the concepts presented through Part IV of the book. The BUDGET programs handle bank deposits and withdrawals for a simulated bank. The user enters a series of bank accounts followed by the deposits and withdrawals for that account. After the user has entered all her transactions, the program displays the balances for each account plus the overall balance. BUDGET2 and BUDGET3 simulate both Checking and Savings accounts. Checking accounts charge a small fee for withdrawals when the balance is less than $500, and savings accounts charge a large fee after the first withdrawal irrespective of the balance. BUDGET2 was an improvement over BUDGET1 in one sense: It isolated the details of account classes from the exterior functions that manipulate accounts. Unfortunately, BUDGET2 contained a large amount of redundancy between the two classes (Savings and Checking); redundancies that you can avoid using the inheritance principles. BUDGET3 adds the following improvements. With the help of the new superhero inheritance and its sidekick polymorphism, you can rationalize the two

Bonus Chapter 1: A Functional Budget Program


account classes into a single class, Account, that captures the commonalties between these two classes. The result is a smaller and simpler set of classes. BUDGET3 also uses a linked list to contain its Account objects rather than the limited fixed array found in the earlier two versions. (I discuss linked lists in Chapter 14.) In addition, the code that goes into BUDGET3 has been divided into separate CPP source modules in different namespaces. (I discuss division of code into modules and namespaces in Chapter 22.)

BC17

Implementing a linked list module


Parts II and III end with a BUDGET program that handles savings and checking account objects. BUDGET1 at the end of Part II uses passive structures, devoid of member functions. This is the type of approach a purely functional programmer might take. Part IIIs BUDGET2 program makes use of active classes with member functions, constructors, and the like. A second problem with both solutions is that they use a fixed array structure to store off the account information. An array is not well suited to handling an unknown number of bank accounts. A better solution is to create a linked list of objects. (Chapter 14 discusses the concept of a linked list.) However, the problems of and solutions to a linked list have nothing to do with bank accounts. Clearly, I can factor out linked list concepts into their own classes. This type of factoring is different but no less important than that discussed earlier in this chapter. It breaks up classes that have the HAS_A relationship into different files where they can be addressed separately. A container such as an array or linked lists HAS_A(n) Account. The interface to this class is defined in the following include file, AccountLinkedList.h:
// AccountLinkedList - maintain a linked list of Account // objects #ifndef _ACCOUNTLINKEDLIST_ #define _ACCOUNTLINKEDLIST_ // the following declaration results from the fact that // Account is not part of the Lists namespace. This problem // goes away in the next version, BUDGET4 in Part V. class Account;

BC18

C++ For Dummies, 5th Edition


namespace Lists { // declare classes in advance class AccountLinkedList; class Node; // LinkedList - represents LinkedList of Node objects class AccountLinkedList { public: AccountLinkedList() { pHead = 0; } void addNode(Node* pNode); Node* firstNode() { return pHead; } protected: Node* pHead; }; // Node - a node within a linked list; each Node points // to an Account object class Node { friend class AccountLinkedList; public: Node(AccountLinkedList* pL, Account* pAcc); // access functions static Node* firstNode(AccountLinkedList* pList) { return pList->firstNode(); } Node* nextNode() { return pNext; } Account* currentAccount() { return pAccount; } protected: AccountLinkedList* pList; Node* pNext; Account* pAccount; }; } #endif

The following AccountLinkedList.cpp file implements a simple linked list of bank accounts (this class is far from a complete implementation):
// AccountLinkedList - maintain a linked list of Account // objects #include AccountLinkedList.h

Bonus Chapter 1: A Functional Budget Program


namespace Lists { Node::Node(AccountLinkedList* pL, Account* pAcc) { pList = pL; pNext = 0; pAccount = pAcc; pL->addNode(this); } // addNode - add a node at the beginning of the current // linked list void AccountLinkedList::addNode(Node* pNode) { pNode->pNext = pHead; pHead = pNode; } }

BC19

A Node object is assigned to each Account. Each Node::pNext pointer points to the next Account in the list. The AccountLinkedList object represents the entire list. AccountLinkedList::pHead points to the first Node in the list of Account objects. For simplicity, the addNode() member function adds Node objects to the beginning of the list.

Taking savings and checking into account


This version of BUDGET will use the linked list contained in AccountLinkedList.cpp as described in Chapter 23. This class allows the program to store and retrieve any number of accounts up to the limit of available memory. The following BUDGET3.cpp is the main module of the BUDGET program. This is the module that contains the actual application code.
// BUDGET3.CPP - BUDGET program with inheritance and // late binding (aka, polymorphism). A // single function can handle both checking // and savings accounts (and any other // accounts that you might invent in the // future). // // In addition, this version stored accounts // in a linked list rather than a fixed array // in order to avoid the limitation of a // fixed maximum number of objects.

BC20

C++ For Dummies, 5th Edition


#include <cstdio> #include <cstdlib> #include <iostream> #include AccountLinkedList.h using namespace std; using namespace Lists; // Account - this abstract class incorporates properties // common to both account types: Checking and // Savings. However, its missing the concept // withdrawal(), which is different between the two class Account { public: Account::Account(AccountLinkedList* pList, int accNo) : node(pList, this), accountNumber(accNo), balance(0) { count++; } // access functions int accountNo() { return accountNumber; } double acntBalance() { return balance; } static int noAccounts() { return count; } // transaction functions void deposit(double amount) { balance += amount; } virtual bool withdrawal(double amount) { if (balance < amount ) { cout << Insufficient funds: balance << balance << , withdrawal << amount << endl; return false; } balance -= amount; return true; } // display function for displaying self on cout void display() { cout << type() << account << accountNumber << = << balance << endl; } virtual char* type() = 0;

Bonus Chapter 1: A Functional Budget Program


protected: // the node retains the linked list information Node node; static int count; unsigned accountNumber; double balance; }; // allocate space for statics int Account::count = 0; // Checking - this class contains properties unique to // checking accounts. Not much left, is there? class Checking : public Account { public: Checking::Checking(AccountLinkedList* pLL, unsigned accNo) : Account(pLL, accNo) { } // overload pure virtual functions virtual bool withdrawal(double amount); virtual char* type() { return Checking; } }; // withdrawal - overload the Account::withdrawal() member // function to charge a 20 cents per check if // the balance is below $500 bool Checking::withdrawal(double amount) { bool success = Account::withdrawal(amount); // if balance falls too low, charge service fee if (success && balance < 500.00) { balance -= 0.20; } return success; } // Savings - same story as Checking except that it also // has a unique data member class Savings : public Account { public: Savings::Savings(AccountLinkedList* pLL, unsigned accNo) : Account(pLL, accNo), noWithdrawals(0) {} // number of accounts

BC21

BC22

C++ For Dummies, 5th Edition


// transaction functions virtual bool withdrawal(double amount); virtual char* type() { return Savings; } protected: int noWithdrawals; }; // withdrawal - overload the Account::withdrawal() member // function to charge a $5.00 fee after the first // withdrawal of the month bool Savings::withdrawal(double amount) { if (++noWithdrawals > 1) { balance -= 5.00; } return Account::withdrawal(amount); } // prototype declarations unsigned getAccntNo(); void process(Account* pAccount); void getAccounts(AccountLinkedList* pLinkedList); void displayResults(AccountLinkedList* pLinkedList); // main - accumulate the initial input and output totals int main(int argcs, char* pArgs[]) { // create a link list to attach accounts to AccountLinkedList* pLinkedList = new AccountLinkedList(); // read accounts from user getAccounts(pLinkedList); // display the linked list of accounts displayResults(pLinkedList); // wait until user is ready before terminating program // to allow the user to see the program results system(PAUSE); return 0; } // getAccounts - load up the specified array of Accounts void getAccounts(AccountLinkedList* pLinkedList) { Account* pA;

Bonus Chapter 1: A Functional Budget Program


// loop until someone enters X or x char accountType; // S or C while (true) { cout << Enter S for Savings, << C for Checking, X for exit:; cin >> accountType; switch (accountType) { case c: case C: pA = new Checking(pLinkedList, getAccntNo()); break; case s: case S: pA = new Savings(pLinkedList, getAccntNo()); break; case x: case X: return; default: cout << I didnt get that.\n; } // now process the object we just created process(pA); } } // displayResults - display the accounts found in the // Account link list void displayResults(AccountLinkedList* pLinkedList) { // now present totals double total = 0.0; cout << \nAccount totals:\n; for (Node* pN = Node::firstNode(pLinkedList); pN != 0; pN = pN->nextNode()) { Account* pA = pN->currentAccount(); pA->display(); total += pA->acntBalance(); } cout << Total worth = << total << \n; }

BC23

BC24

C++ For Dummies, 5th Edition


// getAccntNo - return the account number to create account unsigned getAccntNo() { unsigned accntNo; cout << Enter account number:; cin >> accntNo; return accntNo; } // process(Account) - input the data for an account void process(Account* pAccount) { cout << Enter positive number for deposit,\n << negative for withdrawal, 0 to terminate\n; double transaction; do { cout << :; cin >> transaction; // deposit if (transaction > 0) { pAccount->deposit(transaction); } // withdrawal if (transaction < 0) { pAccount->withdrawal(-transaction); } } while (transaction != 0); }

The first class contained in BUDGET3 is Account. This class encapsulates all the things you know about generic accounts: They are identified by account numbers. Each account carries a balance. Users can make deposits or withdrawals from a bank account. This one class implements the source code that was common between the
Savings and Checking account classes in the BUDGET2 program at the end of Part III. Savings and Checking are now subclasses of Account. I have made Account::type() purely virtual so that it can be overridden appropriately

in the two subclasses. The Account constructor initializes the unique account information by saving off the account number and the initial balance, which is assumed to be zero if

Bonus Chapter 1: A Functional Budget Program


not specified. The constructor also initializes the data member node. The node will be used to link the Account objects together. Logically, you can think of each Account object as hanging from a node in the linked list (more on this in the upcoming discussion of the class Node). The constructor continues by incrementing the static data member count, thereby keeping track of the number of Account objects in existence. Each class has only one copy of a static object: It is shared among all objects. The accountNo() and acntBalance() functions defined next give the outside world the account number and balance information without giving them the ability to modify them directly. The display() and type() functions give all accounts a similar display format. The virtual type() method will be overridden by methods that describe the subclass. For example, Checking::type() returns the string Checking. This is a common trick to allow methods in the base class such as Account::display() to create an accurate description of the class. The Checking subtype of Account is fairly simple. The constructor for Checking does nothing more than pass its arguments to Account. The only real member function is withdrawal(), which implements the rules of engagement for checking accounts. The Savings class is identical to the Checking class in that all it provides is the withdrawal() method. Any subclass of Account that does not override withdrawal() will be virtual you cannot create an instance of a virtual class. The functions that make up the main program are now simplified. The function getAcounts() creates a Savings or Checking account object depending upon the character entered by the user. This is the only place within the main program where the subclass of Account is referred to directly. The displayResults() function loops through the linked list asking each Account object to display itself irrespective of the details of how a savings or checking account (or any other type of account for that matter) might accomplish this. In like fashion, the process() function performs deposits and withdrawals on Account objects. How the specific account handles these operations is left up to the object. The displayResults() method has been modified to handle a linked list rather than an array. The argument to displayResults() is the linked list to read from. The for loop starts with the first object in the list passed to it by

BC25

BC26

C++ For Dummies, 5th Edition


calling Node::firstNode(). The for loop moves from Account object to the next by invoking nextNode(). The loop stops when nextNode() returns a 0. The output from this version is identical to that of its predecessor BUDGET2, except that the accounts display in the reverse order from their appearance. This is because each new account node is added to the front of the list.
Account totals: Savings account 234 = 175 Savings account 123 = 180 Checking account 456 = 580 Checking account 345 = 179.8 Total worth = 1114.8 Press any key to continue

The linked list classes


The linked list is created by two classes, AccountLinkedList and Node, both are defined in the include file AccountLinkedList.h:
// AccountLinkedList - maintain a linked list of Account // objects #ifndef _ACCOUNTLINKEDLIST_ #define _ACCOUNTLINKEDLIST_ // this unfortunate declaration results from the fact that // Account is not part of the Lists namespace. This problem // goes away in the next version, BUDGET4 in Part V. class Account; namespace Lists { // declare classes in advance class AccountLinkedList; class Node; // LinkedList - represents LinkedList of Node objects class AccountLinkedList { public: AccountLinkedList() { pHead = 0; } void addNode(Node* pNode); Node* firstNode() { return pHead; } protected: Node* pHead; };

Bonus Chapter 1: A Functional Budget Program


// Node - a node within a linked list; each Node points // to an Account object class Node { friend class AccountLinkedList; public: Node(AccountLinkedList* pL, Account* pAcc) { pList = pL; pNext = 0; pAccount = pAcc; pL->addNode(this); } static Node* firstNode(AccountLinkedList* pList) { return pList->firstNode(); } Node* nextNode() { return pNext; } Account* currentAccount() { return pAccount; } protected: AccountLinkedList* pList; Node* pNext; Account* pAccount; }; } #endif

BC27

I placed both the AccountLinkedList and Node objects in the Lists namespace to separate them from the Account class. The AccountLinkedList class simply contains the head pointer of the linked list of Node objects. The head pointer is the pointer to the first node in a list. The meat is really in the Node class. Each Node object points to its neighbor through its pNext member. In addition, the node points to an Account object. The pointer pAccount simply refers back to the linked list object itself so that the object knows what linked list it belongs to. Look again at the BUDGET3.cpp source file. main() defined an AccountLinkedList class object this is the linked list. A reference to this list is passed to the constructor for Account. The constructor for Node() that is invoked from the Account constructor creates a node thats a member of the specified linked list and that points to an account. The vestigial AccountLinkedList.cpp source file is present to allow the AccountLinkedList class to reference a method within Node. This definition cannot be placed in the class because Node is defined in the include file after

BC28

C++ For Dummies, 5th Edition


AccountLinkedList. Reversing the order of the class definitions within AccountLinkedList.h doesnt help because Node also refers to the AccountLinkedList class. // AccountLinkedList - maintain a linked list of Account // objects #include AccountLinkedList.h namespace Lists { // addNode - add a node at the beginning of the current // linked list void AccountLinkedList::addNode(Node* pNode) { pNode->pNext = pHead; pHead = pNode; } }

Assessing the budget


The problem that BUDGET solves is fairly simple (and a lot contrived). Nevertheless, comparing the different versions of BUDGET may give you a feel for the differences among a purely functional program (BUDGET1) through an object-based program lacking inheritance (BUDGET2) to a fully object-oriented version (BUDGET3). The main problem with BUDGET3 has nothing to do with the Account class. Rather, the linked list that youve implemented is coupled to the account classes. Having done such a marvelous job, you will want to reuse this linked list in other programs that you might write, programs that have nothing to do with banking (or students, for that matter). BUDGET4 lifts those heavy bonds from the LinkedList class. Youll need the information in Chapter 27 to understand BUDGET4.

BUDGET4
The BUDGET programs handle bank deposits and withdrawals for a simulated bank. The user enters a series of bank accounts followed by the deposits and withdrawals for that account. After the user has entered all her transactions, the program displays the balances for each account plus the overall balance. BUDGET2 and BUDGET3 simulate both Checking and Savings accounts. Checking accounts charge a small fee for withdrawals when the balance is less than $500, and savings accounts charge a large fee after the first withdrawal

Bonus Chapter 1: A Functional Budget Program


irrespective of the balance. BUDGET2 uses function concepts such as those presented through Part II of the book. BUDGET3 uses object-oriented concepts presented in Part IV. BUDGET3 also uses a linked list to contain its Account objects rather than the limited fixed array found in the earlier two versions. (I discuss linked lists in Chapter 14.) Unfortunately, the AccountLinkedList class presented in BUDGET3 is inextricably tied to the Account class. BUDGET4 uses a template to break the bonds of the linked list to any particular class. The template concepts presented in Chapter 27 are used in BUDGET4.

BC29

Implementing linked list as a template class


The following LinkedList template class looks almost identical to the AccountLinkedList classes used in BUDGET3 with the class Node replaced by the generic class T:
// AccountLinkedList - maintain a linked list of Account // objects #ifndef _ACCOUNTLINKEDLIST_ #define _ACCOUNTLINKEDLIST_ // declare base linked list in advance template <class T> class LinkedList; // Node - a node within a linked list; each Node points // to an Account object template <class T> class Node { public: Node(LinkedList<T>* pL, T* pT) { pList = pL; pNext = 0; pObject = pT; } Node<T>* next() { return pNext; } Node<T>* next(Node<T>* pN) { pNext = pN; return pNext; } T* current() { return pObject; }

BC30

C++ For Dummies, 5th Edition


protected: LinkedList<T>* pList; Node<T>* pNext; T* pObject; }; // LinkedList - represents LinkedList of Node objects template <class T> class LinkedList { public: LinkedList<T>() { pFirst = 0; } Node<T>* firstNode() { return pFirst; } Node<T>* lastNode() { // if the list is empty just return a null if (pFirst == 0) { return 0; // empty list; make it first } // else search for the last element in the list Node<T>* pN = pFirst; while(true) { Node<T>* pNext = pN->next(); if (pNext == 0) { break; } pN = pNext; } return pN; } void addNode(Node<T>* pNode) { Node<T>* pN = lastNode(); if (pN == 0) { pFirst = pNode; } else { pN->next(pNode); } } protected: Node<T>* pFirst; }; #endif

Bonus Chapter 1: A Functional Budget Program


In the following discussion, it may help to replace the generic class T with the actual class Account. Youll see how similar this program is to its BUDGET3 predecessor. The odd looking statement, template <class T> class LinkedList, is actually a forward reference that the template class Node will need. Remember that the template classes LinkedList and Node do not become an actual class until the class T is provided. The template class Node is designed to be a node in a linked list. Each node points to an object of class T that will be specified later. The constructor initializes the member pointers properly: pList points to the LinkedList of which this Node is a member, pObject points to the T object, and pNext is initialized to null, indicating that its not yet a member of the list. The active method next(Node<T>*) adds the current node object to the list by initializing pNext pointer. The passive method next() simply returns the next Node<T> in the list. This coding practice is common: An argument-less method fn() returns the current value of the object, whereas fn(T) sets the value based on the argument. This version of addNode() is slightly more sophisticated than that presented in BUDGET3 this version adds the current version to the end of the list. The advantage to this approach is that the objects are read from the list in the order in which they are entered (First In First Out). The disadvantage is that the method lastNode() must search the entire list to find the last element in the list every time an object is added. This can be costly when adding lots of elements to a list.

BC31

Its easy to con-template


The following BUDGET4.CPP is almost identical to its BUDGET3 predecessor:
// BUDGET4.CPP - This version uses a templatized LinkedList // class rather than reinventing the // linked list for every new class. // #include <cstdio> #include <cstdlib> #include <iostream> using namespace std; #include LinkedList.h // Account - this abstract class incorporates properties // common to both account types: Checking and

BC32

C++ For Dummies, 5th Edition


// Savings. However, its missing the concept // withdrawal(), which is different between the two class Account; template class LinkedList<Account>; template class Node<Account>; class Account { public: Account::Account(LinkedList<Account>* pList, unsigned accNo) { // initialize the data members of the object accountNumber = accNo; balance = 0; // add self to the list and count it pNode = new Node<Account>(pList, this); pList->addNode(pNode); count++; } // access functions int accountNo() { return accountNumber; } double acntBalance() { return balance; } static int noAccounts() { return count; } static Account* first(LinkedList<Account>* pLinkedList) { Node<Account>* pNode = pLinkedList->firstNode(); return pNode->current(); } Account* next() { Node<Account>* pNextNode = pNode->next(); return pNextNode->current(); } // transaction functions void deposit(double amount) { balance += amount; } virtual bool withdrawal(double amount) { if (balance < amount ) { cout << Insufficient funds: balance << balance << , withdrawal << amount << endl; return false; } balance -= amount; return true; }

Bonus Chapter 1: A Functional Budget Program


// display function for displaying self on cout void display() { cout << type() << account << accountNumber << = << balance << endl; } virtual char* type() = 0; protected: Node<Account>* pNode; static int count; unsigned accountNumber; double balance; }; // allocate space for statics int Account::count = 0; // Checking - this class contains properties unique to // checking accounts. Not much left, is there? class Checking : public Account { public: Checking::Checking(LinkedList<Account>* pLL, unsigned accNo) : Account(pLL, accNo) { } // overload pure virtual functions virtual bool withdrawal(double amount); virtual char* type() { return Checking; } }; // withdrawal - overload the Account::withdrawal() member // function to charge 20 cents per check if // the balance is below $500 bool Checking::withdrawal(double amount) { bool success = Account::withdrawal(amount); // if balance falls too low, charge service fee if (success && balance < 500.00) { balance -= 0.20; } return success; } // number of accounts

BC33

BC34

C++ For Dummies, 5th Edition


// Savings - same story as Checking except that it also // has a unique data member class Savings : public Account { public: Savings::Savings(LinkedList<Account>* pLL, unsigned accNo) : Account(pLL, accNo) { noWithdrawals = 0; } // transaction functions virtual bool withdrawal(double amount); virtual char* type() { return Savings; } protected: int noWithdrawals; }; // withdrawal - overload the Account::withdrawal() member // function to charge a $5.00 fee after the first // withdrawal of the month bool Savings::withdrawal(double amount) { if (++noWithdrawals > 1) { balance -= 5.00; } return Account::withdrawal(amount); } // prototype declarations unsigned getAccntNo(); void process(Account* pAccount); void getAccounts(LinkedList<Account>* pLinkedList); void displayResults(LinkedList<Account>* pLinkedList); // main - accumulate the initial input and output totals int main(int argcs, char* pArgs[]) { // create a link list to attach accounts to LinkedList<Account> linkedList; // read accounts from user getAccounts(&linkedList); // display the linked list of accounts displayResults(&linkedList);

Bonus Chapter 1: A Functional Budget Program


// wait until user is ready before terminating program // to allow the user to see the program results system(PAUSE); return 0; } // getAccounts - load up the specified array of Accounts void getAccounts(LinkedList<Account>* pLinkedList) { Account* pA; // loop until someone enters X or x char accountType; // S or C while (true) { cout << Enter S for Savings, << C for Checking, X for exit:; cin >> accountType; switch (accountType) { case c: case C: pA = new Checking(pLinkedList, getAccntNo()); break; case s: case S: pA = new Savings(pLinkedList, getAccntNo()); break; case x: case X: return; default: cout << I didnt get that.\n; } // now process the object we just created process(pA); } } // displayResults - display the accounts found in the // Account link list void displayResults(LinkedList<Account>* pLinkedList) { // now present totals double total = 0.0;

BC35

BC36

C++ For Dummies, 5th Edition


cout << \nAccount totals:\n; for (Node<Account>* pN = pLinkedList->firstNode(); pN != 0; pN = pN->next()) { Account* pA = pN->current(); pA->display(); total += pA->acntBalance(); } cout << Total worth = << total << \n; } // getAccntNo - return the account number to create account unsigned getAccntNo() { unsigned accntNo; cout << Enter account number:; cin >> accntNo; return accntNo; } // process(Account) - input the data for an account void process(Account* pAccount) { cout << Enter positive number for deposit,\n << negative for withdrawal, 0 to terminate\n; double transaction; do { cout << :; cin >> transaction; // deposit if (transaction > 0) { pAccount->deposit(transaction); } // withdrawal if (transaction < 0) { pAccount->withdrawal(-transaction); } } while (transaction != 0); }

The first three lines before the definition of the class Account instantiate the template classes LinkedList and Node into the classes LinkedList<Node> and Node<Account>, respectively. These three lines create the classes necessary to link up Account objects into a linked list.

Bonus Chapter 1: A Functional Budget Program


Another program could just as easily create a class LinkedList<Student> or LinkedList<Name>, or . . . you get the idea. The class Account works identically to that presented in BUDGET3 (check out BUDGET3 for an explanation).

BC37

Balancing the template budget


The BUDGET3 program uses the best (well, thats relative) object-oriented techniques to implement a set of account classes AND throws in a linked list implementation that can store an unlimited number of account objects, if you call today. Its problem is that the clever AccountLinkedList class is tied too closely to Account class. BUDGET4 defines a template class LinkedList<class T> that can be used to string up objects (or programmers) of any type. The problem with this version is that it implements a linked list at all. You would think that the problem of linked lists should have come up before this book was ever written. This would be true. A list template class is defined within a set of templates known as the Standard Template Library. In fact, the Standard Template Library defines a whole raft of different containers. The next version of BUDGET uses one of the predefined list template classes to store its Account objects.

BUDGET5
This BUDGET5 program is the last in a long, proud line of programs that all solve the same basic problem: maintaining a list of savings and checking accounts. (Each BUDGET program did the job a little better than its predecessor.) The BUDGET3 program evolved the Account, Savings, and Checking classes about as far as they could go using object-oriented concepts as inheritance. In addition, BUDGET3 maintained its Account objects in a linked list. Unfortunately, this version of the program included an AccountLinkedList class that was dedicated to containing accounts. BUDGET4 released the shackles of Account-itude using the template class LinkedList<class T>.

BC38

C++ For Dummies, 5th Edition


BUDGET5 takes the concept one step further: This version uses one of the containers from the Standard Template Library rather than some homegrown version of linked list. This program requires the reader be familiar with the concepts presented in Chapter 28.

Listing containers
The Standard Template Library (STL) defines a number of different container types that can be used to maintain a group of objects. The simplest list container is the aptly named list. The following version of BUDGET uses the list template class:
// BUDGET5.CPP - Identical to other BUDGET programs except // for the use of an STL list container to // hold budget objects (rather than a fixed // array or a home made linked list) #include <cstdio> #include <cstdlib> #include <iostream> #include <list> using namespace std; // Account - this abstract class incorporates properties // common to both account types: Checking and // Savings. However, its missing the concept // withdrawal(), which is different between the two class Account { public: Account::Account(unsigned accNo) { // initialize the data members of the object accountNumber = accNo; balance = 0; count++; } // access functions int accountNo() { return accountNumber; } double acntBalance() { return balance; } static int noAccounts() { return count; }

Bonus Chapter 1: A Functional Budget Program


// transaction functions void deposit(double amount) { balance += amount; } virtual bool withdrawal(double amount) { if (balance < amount ) { cout << Insufficient funds: balance << balance << , withdrawal << amount << endl; return false; } balance -= amount; return true; } // display function for displaying self on cout void display() { cout << type() << account << accountNumber << = << balance << endl; } virtual char* type() { return Account; } protected: static int count; unsigned accountNumber; double balance; }; // allocate space for statics int Account::count = 0; // Checking - this class contains properties unique to // checking accounts. Not much left, is there? class Checking : public Account { public: Checking::Checking(unsigned accNo) : Account(accNo) { } // overload pure virtual functions virtual bool withdrawal(double amount); virtual char* type() { return Checking; } }; // number of accounts

BC39

BC40

C++ For Dummies, 5th Edition


// withdrawal - overload the Account::withdrawal() member // function to charge 20 cents per check if // the balance is below $500 bool Checking::withdrawal(double amount) { bool success = Account::withdrawal(amount); // if balance falls too low, charge service fee if (success && balance < 500.00) { balance -= 0.20; } return success; } // Savings - same story as Checking except that it also // has a unique data member class Savings : public Account { public: Savings::Savings(unsigned accNo) : Account(accNo) { noWithdrawals = 0; } // transaction functions virtual bool withdrawal(double amount); virtual char* type() { return Savings; } protected: int noWithdrawals; }; // withdrawal - overload the Account::withdrawal() member // function to charge a $5.00 fee after the first // withdrawal of the month bool Savings::withdrawal(double amount) { if (++noWithdrawals > 1) { balance -= 5.00; } return Account::withdrawal(amount); } // AccountPtr - we contain pointers to Account objects // and not to objects themselves typedef Account* AccountPtr;

Bonus Chapter 1: A Functional Budget Program


// prototype declarations unsigned getAccntNo(); void process(AccountPtr pAccount); void getAccounts(list<AccountPtr>& accList); void displayResults(list<AccountPtr>& accList); // main - accumulate the initial input and output totals int main(int argcs, char* pArgs[]) { // create a link list to attach accounts to list<AccountPtr> listAccounts; // read accounts from user getAccounts(listAccounts); // display the linked list of accounts displayResults(listAccounts); // wait until user is ready before terminating program // to allow the user to see the program results system(PAUSE); return 0; } // getAccounts - load up the specified array of Accounts void getAccounts(list<AccountPtr>& accList) { AccountPtr pA; // loop until someone enters X or x char accountType; // S or C while (true) { cout << Enter S for Savings, << C for Checking, X for exit:; cin >> accountType; switch (accountType) { case c: case C: pA = new Checking(getAccntNo()); break; case s: case S: pA = new Savings(getAccntNo()); break;

BC41

BC42

C++ For Dummies, 5th Edition


case x: case X: return; default: cout << I didnt get that.\n; } // now process the object we just created accList.push_back(pA); process(pA); } } // displayResults - display the accounts found in the // Account link list void displayResults(list<AccountPtr>& accntList) { // now present totals double total = 0.0; cout << \nAccount totals:\n; // create an iterator and iterate through the list list<AccountPtr>::iterator iter; iter = accntList.begin(); while(iter != accntList.end()) { AccountPtr pAccount = *iter; iter++; pAccount->display(); total += pAccount->acntBalance(); } cout << Total worth = << total << endl; } // getAccntNo - return the account number to create account unsigned getAccntNo() { unsigned accntNo; cout << Enter account number:; cin >> accntNo; return accntNo; } // process(Account) - input the data for an account void process(AccountPtr pAccount) { cout << Enter positive number for deposit,\n << negative for withdrawal, 0 to terminate\n;

Bonus Chapter 1: A Functional Budget Program


double transaction; do { cout << :; cin >> transaction; // deposit if (transaction > 0) { pAccount->deposit(transaction); } // withdrawal if (transaction < 0) { pAccount->withdrawal(-transaction); } } while (transaction != 0); }

BC43

The include file list contains the definition of the STL list template class (thats logical enough). The Account, Checking, and Savings classes are unchanged from their BUDGET3 and BUDGET4 siblings. The real changes start with the definition of AccountPtr about halfway through the program.

Making a list of the accounts


The main() function creates the list object listAccounts of type list<AccountPtr>. Theoretically, I could have implemented the template class as
list<Account*>, but that rarely works. The pointer hanging off the end of the Account fouls up the definitions within the STL template classes. The definition of AccountPtr avoids these problems. AccountPtr is defined using the typedef keyword to be the same thing as Account*. That is to say, everywhere I write AccountPtr, you can read

pointer to account.
main() passes the list of pointers to Account objects to getAccounts() and to displayResults(). The getAccounts() method adds Account objects to the end of the list by invoking the method push_back().

The displayResults() could remove Account objects from the list by using one of the pop methods; however, that would be whats known as a destructive

BC44

C++ For Dummies, 5th Edition


read. A destructive read actually removes the objects from the list. You want to be able to display the list as many times as you want, or even to process the list some more after youve called displayResults(). A more flexible approach to reading a container is via whats known as an iterator. An iterator is an object that points into the list. The program moves the iterator from one object to the next.
displayResults() defines the iterator iter at the beginning of the while() loop. The assignment iter = accntList.begin() initializes the iter object to the beginning of the list. The value accntList.end() returns the value of the object immediately after the last object. Thus, the while loop has exhausted the loop when iter is equal to accntList.end(). The exoressuib *iter returns the current object. The expression iter++

moves the iterator to the next object in the list. The remainder of the BUDGET5 program is the same as BUDGET4 and BUDGET3 that precede it.

Potrebbero piacerti anche