1 / 55

Chapter 8 Class Relationships

Chapter 8 Class Relationships. Up to this point, the C++ classes that we’ve used have been little more than elaborate structs. We’re now going to examine some of the features of C++ classes that expand the language’s object-oriented capabilities:. Inheritance. Virtual Functions.

nadalia
Télécharger la présentation

Chapter 8 Class Relationships

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 8 Class Relationships Up to this point, the C++ classes that we’ve used have been little more than elaborate structs. We’re now going to examine some of the features of C++ classes that expand the language’s object-oriented capabilities: • Inheritance • Virtual Functions • Class Templates • Overloaded Operators • Function Templates Chapter 8 – Class Relationships

  2. class A A’s public members A’s protected members A’s private members class X: public A class Y: protected A class Z: private A X’s public members Y’s public members Z’s public members A’s public members Y’s protected members Z’s protected members X’s protected members A’s public members A’s protected members Z’s private members A’s protected members A’s public members X’s private members Y’s private members A’s protected members Inheritance When a new class is merely an extension of an existing class, the class may be defined as a “derived” class, which “inherits” from the existing class. Chapter 8 – Class Relationships

  3. Inheritance Example #1: Bank Accounts //////////////////////////////////////////////// // Class definition file: Account.h // // // // In this header file, a class is defined to // // hold information about a bank Account. // // Notice that the only real piece of data // // inside an object of this class is a single // // floating-point number that represents the // // Account's current balance. Again, the // // idea of forming a class like this is to // // hide the information so that it can only // // be accessed through precisely specified // // means, to centralize those means so that // // modifying them at a later date can be sim- // // plified, and to make it easy to formulate // // slight variations of the Account class // // (e.g., a checking Account that accumulates // // interest, a savings Account, etc.). // //////////////////////////////////////////////// #ifndef ACCT_H#include <iostream> using namespace std; class Account{ public: // Class constructors Account(); Account(float initialBalance); Account(const Account &a); // Function members float deposit(float amount); float withdraw(float amount); float getBalance(); Account& operator = (const Account &a); protected: // Data member float balance; }; #define ACCT_H #endif /////////////////////////////////////////////// // Class implementation file: Account.cpp // // // // The implementations of the member func- // // tions of the Account class are contained // // in this program file. // /////////////////////////////////////////////// #include "Account.h"#include <iostream> using namespace std; // Default Constructor: Handles the creation // // of an Account with an unspecified initial // // balance. // Account::Account() { balance = 0.00F; } Chapter 8 – Class Relationships

  4. float Account::withdraw(float amount) { if (amount > balance) return -1.0F; else { balance = balance - amount; return balance; } } // GetBalance Member Function: Retrieves // // the Account balance. This is the only // // way for a function that is not a // // member function of the Account class // // (or one of its derived classes) to // // access the current Account balance. // float Account::getBalance() { return balance; } // Assignment Operator: Overloads the // // assignment operator, so a variable of // // type Account can be used in an assign- // // ment statement. // Account& Account::operator = (const Account &a) { balance = a.balance; return *this; } // Initializing Constructor: Handles the // // creation of an Account with a specified // // initial balance. // Account::Account(float initialBalance) { balance = initialBalance; } // Copy Constructor: Handles the creation // // of an Account that is a duplicate of // // the parameterized Account. // Account::Account(const Account &a) { balance = a.balance; } // Deposit Member Function: Adds a depo- // // sited amt to the balance of an Account. // float Account::deposit(float amount) { balance = balance + amount; return balance; } // Withdraw Member Function: Subtracts a // // withdrawal amt from the balance of an // // Account, returning the modified balance // // if there are sufficient funds and a // // neg. value if insufficient funds exist. // Chapter 8 – Class Relationships

  5. ///////////////////////////////////////////// // Class definition file: CreditAccount.h // // In this header file, a subclass of the // // Account class is defined to hold infor- // // mation about a CreditAccount. All of // // the members of the Account class are // // members of the CreditAccount subclass, // // and the subclass has three additional // // members: an initializing constructor, // // one data member to hold the CreditAc- // // count's daily rate for finance charges, // // and one public member function to apply // // the finance charges to the balance. // ///////////////////////////////////////////// #ifndef CRED_ACCT_H #include "Account.h"#include <iostream> using namespace std; class CreditAccount: public Account { public: // Class constructor CreditAccount(float initialBalance, float finChgRate); // Member function float withdraw(float amount); void applyFinanceCharge(); protected: // Data member float dailyFinChgRate; }; #define CRED_ACCT_H #endif ////////////////////////////////////////////////// // Class implementation file: CreditAccount.cpp // // // // This program file contains the implementa- // // tions of the member functions of the Credit- // // Account subclass of the account class. // ////////////////////////////////////////////////// #include "CreditAccount.h" // The initializing constructor for the Credit- // // Account class invokes the initializing con- // // structor for the Account class, which ini- // // tializes the balance data member. It then // // gives an initial value to the data member // // representing the finance charge rate. // CreditAccount::CreditAccount(float initialBalance, float finChgRate): Account(initialBalance) { dailyFinChgRate = finChgRate; } // The withdraw member function for the Credit- // // Account subclass supercedes the withdraw // // member function for the Account superclass; // // it subtracts a withdrawal amount from the // // balance of a CreditAccount, returning the // // resulting balance (even if it's negative). // float CreditAccount::withdraw(float amount) { balance -= amount; return balance; } Chapter 8 – Class Relationships

  6. class Account PUBLIC: deposit withdraw getBalance = operator PROTECTED: balance class CreditAccount: public Account PUBLIC: withdraw applyFinanceCharge PROTECTED: dailyFinChgRate deposit withdraw getBalance = operator balance //////////////////////////////////////////////// // The applyFinanceCharge member function // // updates a CreditAccount's balance by // // taking the product of the CreditAccount's // // finance charge rate and the amount // // currently owed on the CreditAccount, and // // subtracting that product from the balance. // //////////////////////////////////////////////// void CreditAccount::applyFinanceCharge() { if (getBalance() < 0.0F) withdraw(-1.0F*getBalance()*dailyFinChgRate); } Note that CreditAccount has access to bothwithdraw functions! Chapter 8 – Class Relationships

  7. ///////////////////////////////////////////// // Class definition file: DebitAccount.h // // // // In this header file, a subclass of the // // Account class is defined to hold infor- // // mation about a DebitAccount. All of // // the members of the Account class are // // members of the DebitAccount subclass, // // and the subclass has 3 additional mem- // // bers: an initializing constructor, one // // data member to hold the DebitAccount's // // daily interest rate, and one public // // member function to apply this interest // // rate to the current balance. // ///////////////////////////////////////////// #ifndef DEB_ACCT_H #include "Account.h"#include <iostream> using namespace std; class DebitAccount: public Account { public: // Class constructor DebitAccount(float initialBalance, float intRate); //Member function void compoundInterest(); protected: // Data member float dailyIntRate; }; #define DEB_ACCT_H #endif /////////////////////////////////////////////////// // Class implementation file: DebitAccount.cpp // // // // This program file contains the implementa- // // tions of the member functions of the Debit- // // Account subclass of the Account class. // /////////////////////////////////////////////////// #include "DebitAccount.h"#include <iostream> using namespace std; // The initializing constructor for the Debit- // // Account class invokes the initializing con- // // structor for the Account class, which ini- // // tializes the balance data member. It then // // gives an initial value to the interest data // // member. // DebitAccount::DebitAccount(float initialBalance, float intRate): Account(initialBalance) { dailyIntRate = intRate; } // The compoundInterest function updates a // // DebitAccount's balance by taking the // // product of the incoming interest rate and // // the DebitAccount's balance, and adding // // that product to the balance. // void DebitAccount::compoundInterest() { if (getBalance() > 0.0F) deposit(getBalance() * dailyIntRate); } Chapter 8 – Class Relationships

  8. class Account PUBLIC: deposit withdraw getBalance = operator PROTECTED: balance class DebitAccount: public Account PUBLIC: compoundInterest PROTECTED: dailyIntRate deposit withdraw getBalance = operator balance It’s possible to create a new class that inherits from both the CreditAccount class and the DebitAccount class, but the fact that both inherit from the Account class makes such a move somewhat problematic... Chapter 8 – Class Relationships

  9. ///////////////////////////////////////////////// // Class definition file: DebitCreditAccount.h // // // // In this header file, a subclass of the // // CreditAccount class is defined to hold // // information about an account that is // // essentially both a DebitAccount and a // // CreditAccount. Inheriting members from // // the CreditAccount class, it only needs // // 3 additional members: an initializing // // constructor, a function to compound the // // daily interest on the account, and a data // // member representing a daily interest rate. // ///////////////////////////////////////////////// #ifndef DEB_CRED_ACCT_H #include "CreditAccount.h" class DebitCreditAccount : public CreditAccount { public: // Class constructor DebitCreditAccount(float initialBalance, float intRate, float finChgRate); //Member function void compoundInterest(); protected: // Data member float dailyIntRate; }; #define DEB_CRED_ACCT_H #endif /////////////////////////////////////////// // Class implementation file: // // DebitCreditAccount.cpp // // // // This program file contains the imple- // // mentation of the member function of // // the DebitCreditAccount subclass which // // inherits from the CreditAccount class // // and has additional characteristics of // // the DebitAccount class. // /////////////////////////////////////////// #include "DebitCreditAccount.h" // The DebitCreditAccount initializing // // constructor inherits from the Credit- // // Account initializing constructor, with // // the addition of an initializing assign- // // ment of the dailyIntRate data member. // DebitCreditAccount::DebitCreditAccount (float initialBalance, float intRate, float finChgRate): CreditAccount(initialBalance, finChgRate) { dailyIntRate = intRate; } // The compoundInterest function updates a // // DebitCreditAccount's balance by taking // // the product of the incoming interest // // rate & the DebitCreditAccount's balance,// // and adding that product to the balance. // void DebitCreditAccount::compoundInterest() { if (getBalance() > 0.0F) deposit(getBalance() * dailyIntRate); } Chapter 8 – Class Relationships

  10. class Account PUBLIC: deposit withdraw getBalance = operator class CreditAccount: public Account class DebitCreditAccount: public CreditAccount PROTECTED: balance PUBLIC: withdraw applyFinanceCharge PUBLIC: compoundInterest withdraw applyFinanceCharge deposit withdraw getBalance = operator deposit withdraw getBalance = operator PROTECTED: dailyIntRate PROTECTED: dailyFinChgRate dailyFinChgRate balance balance Chapter 8 – Class Relationships

  11. ////////////////////////////////////////////////// // Program file: DebitCreditDriver.cpp // // This program tests various aspects of the // // Account class and its three subclasses: // // DebitAccount, CreditAccount, and Debit- // // CreditAccount. // ////////////////////////////////////////////////// #include <iostream.h> #include <iomanip.h> #include <fstream.h> #include "DebitAccount.h" #include "CreditAccount.h" #include "DebitCreditAccount.h" void printBalance(const char name[], Account &a); // The main function sets up three variables, // // one of type DebitAccount one of type Credit- // // Account, and one of type DebitCreditAccount. // // It then cycles through a month's banking // // transactions for each Account, comparing // // what the results would be if a person used // // two Accounts (an interest-generating Debit- // // Account in which funds are deposited and a // // finance-charge-generating CreditAccount from // // which money is removed when needed) versus // // if a person used a single DebitCreditAccount,// // which generates interest on those days when // / it has a positive balance and incurs a finance// // charge otherwise. Output messages indicating// // the initial and the final status of each // // Account are generated for a specific sample // // month. // void main() { DebitAccount deb(1000.00F, 0.0001F); CreditAccount cred(0.00F, 0.0005F); DebitCreditAccount deb_cred(1000.00F, 0.0001F, 0.0005F); // The next variable is a floating-point // value that represents a transaction for // the Accounts in question, with positive // numbers used for deposits and negative // numbers used for withdrawals. It is // assumed that a person using the two- // Account approach always applies three- //quarters of any deposited amount to the // CreditAccount, and the other quarter to // the DebitAccount. It is also assumed // that this person retrieves half of each // withdrawn amount from the CreditAccount, // and the other half from the Debit- // Account. float transaction; ifstream inputFile; int nbrOfTransactions; cout.setf(ios::fixed); cout << setprecision(2); cout << "INITIAL STATUS OF ACCOUNTS\n"; printBalance("Debit: ", deb); printBalance("Credit: ", cred); printBalance("Debit-Credit: ", deb_cred); Chapter 8 – Class Relationships

  12. // This section of code loops through the // daily transactions for the three Accounts. inputFile.open("transactions.txt"); nbrOfTransactions = 0; inputFile >> transaction; while (!inputFile.eof()) { nbrOfTransactions++; if (transaction < 0.0F) { deb.withdraw(-0.5F * transaction); cred.withdraw(-0.5F * transaction); deb_cred.withdraw(-transaction); } else if (transaction > 0.0F) { deb.deposit(0.25F * transaction); cred.deposit(0.75F * transaction); deb_cred.deposit(transaction); } deb.compoundInterest(); cred.applyFinanceCharge(); deb_cred.compoundInterest(); deb_cred.applyFinanceCharge(); inputFile >> transaction; } cout << endl << "FINAL STATUS OF ACCOUNTS\n"; printBalance("Debit: ", deb); printBalance("Credit: ", cred); printBalance("Debit-Credit: ", deb_cred); cout << endl; return; } // Function printBalance outputs the // // current balance of the Account. Note // // that it can use an Account as its // // second parameter. // void printBalance(const char header[], Account &a) { cout << header << '$' << a.getBalance() << endl; } 200.00 0.00 0.00 -100.00 0.00 -160.00 -40.00 -600.00 0.00 0.00 -80.00 0.00 0.00 0.00 -600.00 0.00 400.00 0.00 0.00 0.00 200.00 -800.00 0.00 0.00 200.00 0.00 0.00 0.00 -120.00 500.00 Input File: transactions.txt Resulting Output Chapter 8 – Class Relationships

  13. Inheritance Example #2: Weeding Queues // Class declaration file: queue.h // Array implementation of the queue ADT. #ifndef QUEUE_H #include <fstream>using namespace std; typedef int elementType; const MAX_QUEUE_SIZE = 10; class Queue { public: // Class constructors Queue(); Queue(const Queue &q); // Member functions bool isEmpty() const; void enqueue(const elementType &item); elementType dequeue(); void inputEnqueue(ifstream &input); friend ostream& operator << (ostream &destFile, const Queue &q); protected: // Data members int front, rear, length; elementType list[MAX_QUEUE_SIZE]; // Member function bool isFull() const; }; #define QUEUE_H #endif // Class implementation file: Queue.cpp // Array implementation of the Queue ADT. #include "Queue.h" #include <assert.h> // Default constructor: Make empty Queue // Queue:: Queue() { front = 0; rear = MAX_QUEUE_SIZE - 1; length = 0; } // Copy constructor: Make copy of Queue. // Queue:: Queue(const Queue &q) { int index; front = q.front; rear = q.rear; length = q.length; for (int i = 0; i < length; i++) { index = (i + q.front) % MAX_QUEUE_SIZE; list[index] = q.list[index]; } } Chapter 8 – Class Relationships

  14. // InputEnqueue function: inputs items in // // param. file, enqueueing each into *this. // void Queue::inputEnqueue(ifstream &input) { elementType item; input >> item; while (!input.eof()) { enqueue(item); input >> item; } return; } // Output operator: outputs Queue elts to // // parameterized output file, from front // // of Queue to rear, w/o removing items. // ostream& operator << (ostream &destFile, const Queue &q) { int index; for (int i = 0; i < q.length; i++) { index = (i + q.front) % MAX_QUEUE_SIZE; destFile << q.list[index] << endl; } return destFile; } // isFull function; returns bool indicating // // if *this is a full Queue (wrt the array). // bool Queue:: isFull() const { return (length == MAX_QUEUE_SIZE); } // isEmpty function: signals if // // *this is an empty Queue. // bool Queue:: isEmpty() const { return (length == 0); } // Enqueue function; inserts a new // // item into the rear of Queue *this // // (if there's enough room). // void Queue:: enqueue(const elementType &item) { assert(!isFull()); rear = (rear+1) % MAX_QUEUE_SIZE; list[rear] = item; length++; } // Dequeue function; remove the item // // at the front of Queue *this (if // // there’s one there). // elementType Queue:: dequeue() { elementType item; assert(!isEmpty()); item = list[front]; front = (front+1) % MAX_QUEUE_SIZE; length--; return item; } Chapter 8 – Class Relationships

  15. void WeedingQueue:: enqueue(const elementType &item) { int index; if (isFull()) { // Locate the smallest element. int minIndex = 0; for (index = 1; index < length; index++) if (list[(front+index) % MAX_QUEUE_SIZE] < list[(front+minIndex) % MAX_QUEUE_SIZE]) minIndex = index; // If the new item is smaller, don't insert it. if (item < list[(front+minIndex)%MAX_QUEUE_SIZE]) return; // Otherwise, remove the smallest element. for (index = minIndex; index < length; index++) list[(front + index) % MAX_QUEUE_SIZE] = list[(front + index + 1) % MAX_QUEUE_SIZE]; length--; rear = (front + length - 1) % MAX_QUEUE_SIZE; } // Now insert the new element. rear = (rear+1) % MAX_QUEUE_SIZE; list[rear] = item; length++; } // Class declaration file: WeedingQueue.h // This subclass of the Queue class; // "weeds" out smaller values whenever // the structure is about to overflow. #ifndef WEEDING_QUEUE_H #include "Queue.h"using namespace std; class WeedingQueue: public Queue { public: // Member function void enqueue(const elementType &item); }; #define WEEDING_QUEUE_H #endif // Class implementation file: // WeedingQueue.cpp // This subclass of the Queue class; // "weeds" out smaller values whenever // the structure is about to overflow. #include "WeedingQueue.h" // Enqueue function; inserts a new item // // in the rear of WeedingQueue *this (if // // there's enough room). If there isn’t // // enough room, the smallest element in // // the WeedingQueue is removed (even if // // it's not at the front of the Weeding- // // Queue), and then the new item is in- // // serted at the rear of the WeedingQueue.// Chapter 8 – Class Relationships

  16. // Program file: FirstQueueDriver.cpp // // This program tests the WeedingQueue // // class by inserting 50 values via // // direct input with an eof check. // #include <iostream.h> #include <fstream.h> #include "WeedingQueue.h" // The main function inputs and // // outputs a WeedingQueue. // void main() { WeedingQueue wq; ifstream inputFile; elementType item; inputFile.open("queueData.txt"); inputFile >> item; while (!inputFile.eof()) { wq.enqueue(item); inputFile >> item; } cout << wq; return; } 33 56 82 90 47 10 94 36 89 21 88 35 91 17 53 28 59 82 36 72 16 38 78 92 73 16 83 95 19 66 46 20 39 65 48 27 63 49 14 84 62 31 93 38 77 80 11 98 67 45 Contents of queueData.txt Resulting interactive session Chapter 8 – Class Relationships

  17. // Program file: SecondQueueDriver.cpp // // This program tests the WeedingQueue // // class by inserting 50 values via // // the inputEnqueue member function. // #include <iostream.h> #include <fstream.h> #include "WeedingQueue.h" // The main function inputs and // // outputs a WeedingQueue. // void main() { WeedingQueue wq; ifstream inputFile; inputFile.open("queueData.txt"); wq.inputEnqueue(inputFile); cout << wq; return; } 33 56 82 90 47 10 94 36 89 21 88 35 91 17 53 28 59 82 36 72 16 38 78 92 73 16 83 95 19 66 46 20 39 65 48 27 63 49 14 84 62 31 93 38 77 80 11 98 67 45 Contents of queueData.txt Resulting interactive session Why did this crash? Chapter 8 – Class Relationships

  18. Virtual Functions and Late Binding The problem in the previous example relates to the fact that the WeedingQueue subclass used the inputEnqueue function that it inherited from the Queue class. void Queue::inputEnqueue(ifstream &input) { elementType item; input >> item; while (!input.eof()) { enqueue(item); input >> item; } return; } When the compiler analyzes this code, it’s doing it in the context of the Queue class. Consequently, it “binds” this line to the enqueue member function of the Queue class, not the enqueue member function of the WeedingQueue subclass! Chapter 8 – Class Relationships

  19. // Class declaration file: queue.h // Array implementation of the queue ADT. #ifndef QUEUE_H #include <fstream.h> typedef int elementType; const MAX_QUEUE_SIZE = 10; class Queue { public: // Class constructors Queue(); Queue(const Queue &q); // Member functions bool isEmpty() const; virtualvoid enqueue(const elementType &item); elementType dequeue(); void inputEnqueue(ifstream &input); friend ostream& operator << (ostream &destFile, const Queue &q); protected: // Data members int front, rear, length; elementType list[MAX_QUEUE_SIZE]; // Member function bool isFull() const; }; #define QUEUE_H #endif // Class declaration file: WeedingQueue.h // This subclass of the Queue class; // "weeds" out smaller values whenever // the structure is about to overflow. #ifndef WEEDING_QUEUE_H #include "Queue.h" class WeedingQueue: public Queue { public: // Member function virtual void enqueue(const elementType &item); }; #define WEEDING_QUEUE_H #endif To ensure that the correct context is used, declare each version of enqueue as a “virtual” function. Then binding won’t occur until execution time! Chapter 8 – Class Relationships

  20. Notice that labeling the enqueue functions as virtual did the trick! Generally, follow these guidelines when deciding whether to make a member function virtual: • Make the functions of the superclass virtual, so they can be overridden. • Never make constructors virtual. • Always make destructors virtual. Chapter 8 – Class Relationships

  21. Templates C++ provides a mechanism for avoiding redundancy in the creation of classes and functions. Swap Function for double Linked List Class for long int Linked List Class for int Linked List Class for bankAcct Swap Function for string Swap Function for matrix Linked List Class for bool Linked List Class for float Linked List Class for queue Swap Function for int Swap Function for stack Linked List Class for matrix Swap Function for float Linked List Class for double Linked List Class for nodePtr Swap Function for char Linked List Class for string Swap Function for bool Linked List Class for char Linked List Class for stack Swap Function for queue Chapter 8 – Class Relationships

  22. topGap indent1 midGap height indent2 Class Template Example: The Two-Field Label The two-field label class template will allow two values, field1 and field2, to be placed into a label that can be output. It is assumed that the types of fields1 and fields2 have a member function getLineNumber that takes an integer parameter and returns the corresponding line of the field, as well as a member function height that returns the number of output lines required by the field. field1 field2 Chapter 8 – Class Relationships

  23. Definition & Implementation of the Two-Field Label Class // Member functions E1 getField1() const {return field1;} E2 getField2() const {return field2;} int getIndent1() const {return indent1;} int getIndent2() const {return indent2;} int getHeight() const {return height;} int getTopGap() const {return topGap;} int getMidGap() const {return midGap;} void setField1(const E1 &fd1) {field1 = fd1;} void setField2(const E2 &fd2) {field2 = fd2;} void setIndent1(int in1) {indent1 = (in1 < 0) ? 0 : in1;} void setIndent2(int in2) {indent2 = (in2 < 0) ? 0 : in2;} void setHeight(int h) {height = (h < 0) ? 0 : h;} void setTopGap(int tg) {topGap = (tg < 0) ? 0 : tg;} void setMidGap(int mg) {midGap = (mg < 0) ? 0 : mg;} //////////////////////////////////////////////////// // Class definition file: TwoFieldLabel.h // // // // This file defines the two-field label class of // // objects. Each two-field label contains two // // template-based fields that will be displayed // // in a rectangular region. This region will // // have a specified width and height, as well as // // an indentation for each field, a vertical gap // // between the fields, and a gap between the top // // of the rectangular region and the first field. // // An output operator is also specified for the // // two-field label. // //////////////////////////////////////////////////// #ifndef TWO_FIELD_LABEL_H #include <iostream> const int MIN_LABEL_HEIGHT = 3; /*** DEFINITION SECTION ***/ template <class E1, class E2> class twoFieldLabel { public: // Constructors twoFieldLabel(); twoFieldLabel(int in1, int in2, int tg, int mg); twoFieldLabel(int h); twoFieldLabel(E1 f1, E2 f2); twoFieldLabel(const twoFieldLabel<E1, E2> &tfl); Chapter 8 – Class Relationships

  24. // Initializing constructor: Sets *this to // // have the parameterized gap sizes and in- // // dentations, no field values, and minimal // // height to accommodate gap sizes. // template <class E1, class E2> twoFieldLabel<E1, E2>::twoFieldLabel(int in1, int in2, int tg, int mg) { indent1 = (in1 < 0) ? 0 : in1; indent2 = (in2 < 0) ? 0 : in2; topGap = (tg < 0) ? 0 : tg; midGap = (mg < 1) ? 1 : mg; height = topGap + midGap + 2; } // Initializing constructor: Sets *this to // // have the parameterized gap sizes and in- // // dentations, no field values, and minimal // // height to accommodate gap sizes. // template <class E1, class E2> twoFieldLabel<E1, E2>::twoFieldLabel(int h) { height = h; indent1 = indent2 = topGap = 0; midGap = 1; height = (h < MIN_LABEL_HEIGHT) ? MIN_LABEL_HEIGHT : h; } friend ostream& operator << (ostream &os, const twoFieldLabel<E1, E2> &tfl); private: // Data members E1 field1; E2 field2; int indent1; int indent2; int height; int topGap; int midGap; }; /*** IMPLEMENTATION SECTION ***/ // Default constructor: Sets *this to // // have minimal height, gap sizes, and // // indentations, and no field values. // template <class E1, class E2> twoFieldLabel<E1, E2>::twoFieldLabel() { height = MIN_LABEL_HEIGHT; indent1 = indent2 = topGap = 0; midGap = 1; } Chapter 8 – Class Relationships

  25. template <class E1, class E2> ostream& operator << (ostream &os, const twoFieldLabel<E1, E2> &tfl) { int i, j; int bottomGap = tfl.getHeight() - tfl.getTopGap() - tfl.getField1().height() - tfl.getMidGap() - tfl.getField2().height(); for (i = 1; i <= tfl.getTopGap(); i++) os << endl; for (i=1; i <= tfl.getField1().height(); i++) { for (j=1; j <= tfl.getIndent1(); j++) os << ' '; os << tfl.getField1().getLineNumber(i) << endl; } for (i=1; i <= tfl.getMidGap(); i++) os << endl; for (i=1; i <= tfl.getField2().height(); i++) { for (j=1; j <= tfl.getIndent2(); j++) os << ' '; os << tfl.getField2().getLineNumber(i) << endl; } for (i=1; i <= bottomGap; i++) os << endl; return os; } #define TWO_FIELD_LABEL_H #endif // Initializing constructor: Sets *this to // // have the parameterized field values, // // minimal height to accommodate the fields, // // and minimal gap sizes and indentation. // template <class E1, class E2> twoFieldLabel<E1, E2>::twoFieldLabel(E1 f1, E2 f2) { height = f1.height() + f2.height() + 1; indent1 = indent2 = topGap = 0; midGap = 1; field1 = f1; field2 = f2; } // Copy constructor: copies the field // // values, gap sizes, indentations and // // heights from the parameterized // // twoFaceLabel into *this. // template <class E1, class E2> twoFieldLabel<E1, E2>::twoFieldLabel (const twoFieldLabel<E1, E2> &tfl) { height = tfl.getHeight(); indent1 = tfl.getIndent1(); indent2 = tfl.getIndent2(); topGap = tfl.getTopGap(); midGap = tfl.getMidGap(); field1 = tfl.getField1(); field2 = tfl.getField2(); } // The output operator is overloaded to ap- // // propriately format the two-field label. // Chapter 8 – Class Relationships

  26. New Person Class for Use in the Two-Field Label Class //////////////////////////////////////////////// // Class implementation file: Person.h // // This program file contains the definitions // // of the members of the person class, which // // consists of three strings representing a // // person's name and address information. // //////////////////////////////////////////////// #ifndef PERSON_H #include <string> using namespace std; const int NBR_OF_OUTPUT_LINES = 3; class person { public: // Constructors person(); person(const person &p); person(string fnm, string ad1, string ad2); // Member functions int height(); string getLineNumber(int i); protected: // Data members string fullName; string firstAddressLine; string secondAddressLine;}; #define PERSON_H #endif /////////////////////////////////////////// // Class implementation file: Person.cpp // // // // This program file contains the actual // // implementations of the member func- // // tions of the person class defined in // // the Person.h header file. // /////////////////////////////////////////// #include "Person.h" #include <string> using namespace std; // The default constructor sets the // // 3 data members to empty strings. // person::person() { fullName = firstAddressLine = secondAddressLine = ""; } // The copy constructor sets the 3 data // // members to the corresponding data // // member values of the param. person. // person::person(const person &p) { fullName = p.fullName; firstAddressLine = p.firstAddressLine; secondAddressLine = p.secondAddressLine; } Chapter 8 – Class Relationships

  27. Notice that the person class has the required getLineNumber & height member functions. // The initializing constructor sets // // the three data members of *this to // // the parameterized string values. // person::person(string fnm, string ad1, string ad2) { fullName = fnm; firstAddressLine = ad1; secondAddressLine = ad2; } // The height member function returns // // the number of output lines that are // // needed to output the person *this. // int person::height() { return NBR_OF_OUTPUT_LINES; } // The getLineNumber member function returns // // the appropriate addressing line, depending // // upon the value of the integer parameter. // string person::getLineNumber(int i) { switch (i) { case 3: return secondAddressLine; break; case 2: return firstAddressLine; break; default: return fullName; break; } } Chapter 8 – Class Relationships

  28. New Monetary Class for Use in the Two-Field Label Class //////////////////////////////////////////// // Class definition file: Monetary.h // // // // This program file contains the defini- // // tions of the members of the monetary // // class, which consists of a float value // // representing dollars and cents. // //////////////////////////////////////////// #ifndef MONETARY_H #include <string> using namespace std; class monetary { public: // Constructors monetary(); monetary(const float &amt); monetary(const monetary &m); // Member functions int height(); string getLineNumber(int i); protected: // Data member float amount; }; #define MONETARY_H #endif ///////////////////////////////////////////// // Class implementation file: Monetary.cpp // // This program file contains the actual // // implementations of the member functions // // of the monetary class defined in the // // Monetary.h header file. // ///////////////////////////////////////////// #include "Monetary.h" #include <string> using namespace std; // The default constructor sets // // the monetary amount to zero. // monetary::monetary() { amount = 0.00F; } // The initializing constructor sets the // // monetary amount to the param. value. // monetary::monetary(const float &amt) { amount = amt; } // The copy constructor sets the monetary // // amt to that of the param monetary value. // monetary::monetary(const monetary &m) { amount = m.amount; } Chapter 8 – Class Relationships

  29. Notice that the monetary class has the required getLineNumber & height member functions. // The height member function returns the number of output // // lines that are needed to output the monetary *this. // int monetary::height() { return 1; } // The getLineNumber member function converts the monetary's amount into // // a string corresponding to the appropriate amount of dollars and cents. // string monetary::getLineNumber(int i) { string s = "$"; string reverseDollarText = ""; int dollars = (int)amount; int cents = (int)(100 * (amount - dollars)); int digit; if (dollars == 0) s += '0'; else { while (dollars > 0) { digit = dollars % 10; dollars /= 10; reverseDollarText += ('0' + digit); } for (i = reverseDollarText.length() - 1; i >= 0; i--) s += (reverseDollarText[i]); } s += '.'; s += ('0' + (cents / 10)); s += ('0' + (cents % 10)); return s; } Chapter 8 – Class Relationships

  30. New LabelString Class for Use in the Two-Field Label Class ////////////////////////////////////////// // Class definition file: LabelString.h // // // // This program file contains the defi- // // nitions of the members of the label- // // String class,which consists of a // // single string value. // ////////////////////////////////////////// #ifndef LABEL_STRING_H #include <string> using namespace std; class labelString { public: // Constructors labelString(); labelString(const char str[]); labelString(const string &str); labelString(const labelString &ls); // Member functions int height(); string getLineNumber(int i); protected: // Data member string text; }; #define LABEL_STRING_H #endif //////////////////////////////////////////////// // Class implementation file: LabelString.cpp // // This program file contains the actual im- // // plementations of the member functions of // // the labelString class defined in the // // LabelString.h header file. // //////////////////////////////////////////////// #include <string> #include "LabelString.h" using namespace std; // The copy constructor sets the labelString's // // text data member to an empty string. // labelString::labelString() { text = ""; } // This initializing constructor sets the text // // data member to the param. character array. // labelString::labelString(const char str[]) { text = str; } // This initializing constructor sets the text // // data member to the param. string value. // labelString::labelString(const string &str) { text = str; } Chapter 8 – Class Relationships

  31. Notice that the labelString class has the required getLineNumber & height member functions. // The copy constructor sets the *this label- // // String's text data member to the parameter- // // ized labelString's text data member. // labelString::labelString(const labelString &ls) { text = ls.text; } // The height member function returns the // // number of output lines that are needed // // to output the labelString *this. // int labelString::height() { return 1; } // The getLineNumber member function disregards // // the integer parameter and merely retrieves // // the text data member of the *this labelString. // string labelString::getLineNumber(int i) { return text; } Chapter 8 – Class Relationships

  32. Driver Using a Two-Field Label with Two Person Fields ///////////////////////////////////////////////////////////////////// // Program file: MailingLabelDriver.cpp // // // // This driver program retrieves destination addresses for several // // customers from an external file, and then generates an output // // file of mailing labels for these items, using a user-supplied // // source address and the retrieved destination addresses. // ///////////////////////////////////////////////////////////////////// #include "Person.h" #include "TwoFieldLabel.h" #include <iostream> #include <string> #include <fstream> using namespace std; const int MAX_STRING_SIZE = 40; const int MAX_FILENAME_SIZE = 80; const int RTRN_ADDR_INDENT = 2; const int DEST_ADDR_INDENT = 25; const int TOP_GAP = 2; const int MIDDLE_GAP = 8; const int LABEL_HEIGHT = 20; void queryUser(person &p, char inputFileName[], char outputFileName[]); void createLabels(person source, ifstream &personFile, ofstream &labelFile); twoFieldLabel<person, person> generateLabel(const person &source, const person &destination); Chapter 8 – Class Relationships

  33. // The main function queries the user for source & destination // // info, and generates the output file of mailing labels. // void main() { person source; char personFileName[MAX_FILENAME_SIZE]; char labelFileName[MAX_FILENAME_SIZE]; ifstream personFile; ofstream labelFile; queryUser(source, personFileName, labelFileName); personFile.open(personFileName); labelFile.open(labelFileName); createLabels(source, personFile, labelFile); personFile.close(); labelFile.close(); return; } Chapter 8 – Class Relationships

  34. // Function queryUser queries the user for the source person info, the name of // // the input file containing the data regarding each destination person, and // // the name of the output file for the labels that are being generated. // void queryUser(person &p, char inputFileName[], char outputFileName[]) { char name[MAX_STRING_SIZE], addr[MAX_STRING_SIZE], site[MAX_STRING_SIZE]; cout << "Enter the full name of the sender: "; cin.getline(name, MAX_STRING_SIZE); while string(name) == "") cin.getline(name, MAX_STRING_SIZE); cout << "Enter the street address of the sender: "; cin.getline(addr, MAX_STRING_SIZE); while (string(addr) == "") cin.getline(addr, MAX_STRING_SIZE); cout << "Enter the city, state, and zip code of the sender: "; cin.getline(site, MAX_STRING_SIZE); while (string(site) == "") cin.getline(site, MAX_STRING_SIZE); p = person(name, addr, site); cout << "Enter the name of the file where the destination addresses reside: "; cin >> inputFileName; cout << "Enter the name of the file where the mailing labels should be placed: "; cin >> outputFileName; cout << endl << endl; } Chapter 8 – Class Relationships

  35. // The createLabels function reads all of the person data from the input file, // // and generates a mailing label to each person, with the source parameter as // // the return address. Each label is then written to the output file. // void createLabels(person source, ifstream &personFile, ofstream &labelFile) { twoFieldLabel<person, person> label; person destination; char name[MAX_STRING_SIZE], addr[MAX_STRING_SIZE], site[MAX_STRING_SIZE]; personFile.getline(name, MAX_STRING_SIZE); while ((string(name) == "") && !personFile.eof()) personFile.getline(name, MAX_STRING_SIZE); while (!personFile.eof()) { personFile.getline(addr, MAX_STRING_SIZE); while (string(addr) == "") personFile.getline(addr, MAX_STRING_SIZE); personFile.getline(site, MAX_STRING_SIZE); while (string(site) == "") personFile.getline(site, MAX_STRING_SIZE); destination = person(name, addr, site); label = generateLabel(source, destination); labelFile << label << endl; for (int i = 1; i <= DEST_ADDR_INDENT+MAX_STRING_SIZE; i++) labelFile << '-'; personFile.getline(name, MAX_STRING_SIZE); while ((string(name) == "") && !personFile.eof()) personFile.getline(name, MAX_STRING_SIZE); } } Chapter 8 – Class Relationships

  36. Darth Vader 666 Imperial Lane Coruscant, CA 90210 Fred Flintstone One Million BC Lane Bedrock CA 00000 ----------------------------------------------------------------- Darth Vader 666 Imperial Lane Coruscant, CA 90210 Marge Simpson 417 Evergreen Street Springfield IL 36963 ----------------------------------------------------------------- Darth Vader 666 Imperial Lane Coruscant, CA 90210 ... Fred Flintstone One Million BC Lane Bedrock CA 00000 Marge Simpson 417 Evergreen Street Springfield IL 36963 Ren Hoek 1237 Stimpy Avenue Mudskipper WI 86420 Scooby Doo 666 Shaggy Drive Amityville MA 75421 ... // Function generateLabel produces the two-field // // label that will serve as a mailing label. // twoFieldLabel<person, person> generateLabel(const person &source, const person &destination) { twoFieldLabel<person, person> label(RTRN_ADDR_INDENT, DEST_ADDR_INDENT, TOP_GAP, MIDDLE_GAP); label.setHeight(LABEL_HEIGHT); label.setField1(source); label.setField2(destination); return label; } LBL.txt Addresses.txt Chapter 8 – Class Relationships

  37. Driver Using a Two-Field Label w/ LabelString & Monetary Fields /////////////////////////////////////////////////////////////////////////// // Program file: PriceTagDriver.cpp // // This driver program retrieves inventory numbers, prices, and amounts // // for several items of merchandise from an interactive session with the // // user, and then generates a file of price tag labels for these items. // /////////////////////////////////////////////////////////////////////////// #include "Monetary.h“ #include "LabelString.h" #include "TwoFieldLabel.h" #include <iostream> #include <fstream> bool queryUser(labelString &ls, monetary &m, int &inventorySize, char outputFileName[]); twoFieldLabel<labelString, monetary> generateLabel(const labelString &ls, const monetary &m); Chapter 8 – Class Relationships

  38. // The main function repeatedly asks the user whether or not to // // generate more price tags, and generates them in the user-specified // // destination files until the user says to stop. // void main() { twoFieldLabel<labelString, monetary> label; labelString itemNumber; monetary itemPrice; int itemInventorySize; char labelFileName[80]; ofstream labelFile; while (queryUser(itemNumber, itemPrice, itemInventorySize, labelFileName)) { labelFile.open(labelFileName); label = generateLabel(itemNumber, itemPrice); for (int i = 1; i <= itemInventorySize; i++) labelFile << label << "***************" << endl;; labelFile.close(); } return; } Chapter 8 – Class Relationships

  39. // Function queryUser queries the user for the inventory number, price, amt. // // of stock, and output file name for the labels that are being generated. // bool queryUser(labelString &ls, monetary &m, int &inventorySize, char outputFileName[]) { char YorN; string invNbr; float price; cout << endl << "Would you like to generate some price tags? (Enter Y or N:) "; cin >> YorN; if ((YorN == 'y') || (YorN == 'Y')) { cout << "Please enter the inventory number: "; cin >> invNbr; ls = invNbr; cout << "Please enter the price of the item in question: $"; cin >> price; m = price; cout << "Please enter the number of price tags you wish to produce: "; cin >> inventorySize; cout << "Please enter the name of the file " << "where the price tags should be placed: "; cin >> outputFileName; return true; } else return false; } Chapter 8 – Class Relationships

  40. // Function generateLabel produces the two-field // // label that will serve as a price tag. // twoFieldLabel<labelString, monetary> generateLabel (const labelString &ls, const monetary &m) { twoFieldLabel<labelString, monetary> label(5); label.setField1(ls); label.setField2(m); return label; } ABC-789 $511.07 *************** ABC-789 $511.07 *************** ABC-789 $511.07 *************** ABC-789 $511.07 *************** ABC-789 $511.07 *************** XYZ-123 $14.94 *************** XYZ-123 $14.94 *************** XYZ-123 $14.94 *************** XYZ.txt ABC.txt Chapter 8 – Class Relationships

  41. Driver Using a Two-Field Label with LabelString & Person Fields ///////////////////////////////////////////////////////////////////// // Program file: PersonnelFileDriver.cpp // // // // This driver program retrieves personnel information (SSN, name, // // department number, mailstop) from an external file, and then // // generates an output file of folder labels for these employees, // // alternating between three different indentations. // ///////////////////////////////////////////////////////////////////// #include "Person.h" #include "TwoFieldLabel.h" #include "LabelString.h" #include <iostream> #include <string> #include <fstream> using namespace std; const int MAX_STRING_SIZE = 20; const int MAX_FILENAME_SIZE = 40; const int NBR_LABEL_STYLES = 4; void queryUser(char inputFileName[], char outputFileName[]); void generateLabelFile(ifstream &employeeFile, ofstream &labelFile); twoFieldLabel<labelString, person> generateLabel(const labelString &ssn, const person &employee); Chapter 8 – Class Relationships

  42. // The main function opens the I/O files, retrieves the employee data // // from the input file, and generates the output file of labels. // void main() { char employeeFileName[MAX_FILENAME_SIZE]; char labelFileName[MAX_FILENAME_SIZE]; ifstream employeeFile; ofstream labelFile; queryUser(employeeFileName, labelFileName); employeeFile.open(employeeFileName); labelFile.open(labelFileName); generateLabelFile(employeeFile, labelFile); employeeFile.close(); labelFile.close(); return; } // Function queryUser queries the user for the names of the input file contain- // // ing the employee data and the output file for the labels being generated. // void queryUser(char inputFileName[], char outputFileName[]) { cout << "Enter the name of the file containing the employee information: "; cin >> inputFileName; cout << "Enter the name of the file where the “ << "personnel folder labels should go: "; cin >> outputFileName; cout << endl << endl; } Chapter 8 – Class Relationships

  43. // The generateLabelFile function reads the person data from // // the parameterized input file, & generates the folder labels // // that are written to the parameterized output file. // void generateLabelFile(ifstream &employeeFile, ofstream &labelFile) { twoFieldLabel<labelString, person> label; labelString labelSSN; string ssn; char name[MAX_STRING_SIZE], dept[MAX_STRING_SIZE], mail[MAX_STRING_SIZE]; person employee; int indent = 0; int separatorLength = NBR_LABEL_STYLES * MAX_STRING_SIZE; employeeFile >> ssn; while (!employeeFile.eof()) { labelSSN = labelString(ssn); employeeFile.getline(name, MAX_STRING_SIZE); while (string(name) == "") employeeFile.getline(name, MAX_STRING_SIZE); employeeFile.getline(dept, MAX_STRING_SIZE); while (string(dept) == "") employeeFile.getline(dept, MAX_STRING_SIZE); employeeFile.getline(mail, MAX_STRING_SIZE); while (string(mail) == "") employeeFile.getline(mail, MAX_STRING_SIZE); Chapter 8 – Class Relationships

  44. employee = person(name, dept, mail); label = generateLabel(labelSSN, employee); label.setIndent1(indent); label.setIndent2(indent); labelFile << label << endl; for (int i = 1; i <= separatorLength; i++) labelFile << '+'; labelFile << endl; indent = (indent + MAX_STRING_SIZE) % separatorLength; employeeFile >> ssn; } } // Function generateLabel produces the two-field label // // that will serve as a personnel folder label. // twoFieldLabel<labelString, person> generateLabel(const labelString &ssn, const person &employee) { twoFieldLabel<labelString, person> label(ssn, employee); return label; } Chapter 8 – Class Relationships

  45. 223-66-9032 Elroy Jetson Dept. 63B Mailstop 5031 221-80-9076 Lisa Simpson Dept. 12C Mailstop 1654 177-72-7874 Harley Quinn Dept. 33B Mailstop 920 223-43-8190 Scrappy Doo Dept. 71A Mailstop 1902 222-22-2222 Harvey Dent Dept. 22B Mailstop 2222 220-53-8068 Wile E. Coyote Dept. 43D Mailstop 3117 223-66-9032 Elroy Jetson Dept. 63B Mailstop 5031 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 221-80-9076 Lisa Simpson Dept. 12C Mailstop 1654 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 177-72-7874 Harley Quinn Dept. 33B Mailstop 920 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 223-43-8190 Scrappy Doo Dept. 71A Mailstop 1902 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 222-22-2222 Harvey Dent Dept. 22B Mailstop 2222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 220-53-8068 Wile E. Coyote Dept. 43D Mailstop 3117 ++++++++++++++++++++++++++++++++++++++ 221-91-0253 Maggie Simpson Dept. 12C Mailstop 1655 127-55-7293 Pebbles Flintstone Dept. 33A Mailstop 2825 637-44-1099 Daisy Duck Dept. 18C Mailstop 3101 634-29-2906 Minnie Mouse Dept. 18B Mailstop 3096 224-64-1457 Betty Rubble Dept. 41D Mailstop 1782 772-25-2765 Quick Draw McGraw Dept. 86X Mailstop 3210 FLDR.txt employees.txt Chapter 8 – Class Relationships

  46. Overloaded Operators As we’ve seen, when we create a new class, we can overload many of the operators that we’re accustomed to using with other C++ classes. /////////////////////////////////////////// // Class Definition File: date.h // // The class definition file for the // // Date class, including the definition // // of the DayOfWeek enumerated type. // /////////////////////////////////////////// #ifndef DATE_H #include <fstream>using namespace std; class Date { public: Date(); Date(int m, int d, int y); bool setDate(int m, int d, int y); int getMonth() const; int getDay() const; int getYear() const; bool operator == (const Date &d) const; bool operator != (const Date &d) const; bool operator < (const Date &d) const; bool operator <= (const Date &d) const; bool operator > (const Date &d) const; bool operator >= (const Date &d) const; friend ostream& operator << (ostream &file, const Date &d); private: int month; int day; int year; }; #define DATE_H #endif Overloaded Output Operator Overloaded Equality & Inequality Operators Chapter 8 – Class Relationships

  47. // The initializing constructor for the Date // // class initializes *this with the parameter- // // ized values if they are legitimate calendar // // date values; if not, it sets *this to // // today's month, day, and year (as calculated // // via the functions in time.h). // Date::Date(int m, int d, int y) { bool validDate = false; switch (m) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: { validDate = ((d>=1) && (d<=31)); break; } case 4: case 6: case 9: case 11: { validDate = ((d>=1) && (d<=30)); break; } case 2: { if ((y%4==0) && ((y%100!=0) || (y%400==0))) validDate = ((d>=1)&&(d<=29)); else validDate = ((d>=1)&&(d<=28)); break; } } if (validDate) { month = m; day = d; year = y; } //////////////////////////////////////////// // Class Implementation File: date.cpp // // // // The class implementation file for the // // Date class, used to hold calendar date // // information and to calculate the day // // of the week for a particular date, to // // determine if the date is a weekday or // // part of a weekend, and to figure out // // if the date is a national holiday. // //////////////////////////////////////////// #include "date.h" #include <ctime> #include <iomanip> #include <fstream> using namespace std; // The default constructor for the Date // // class sets *this to today's month, // // day, and year (as calculated via the // // functions in time.h). // Date::Date() { struct tm *newtime; long int t; time( &t ); newtime = localtime( &t ); month = (newtime->tm_mon) + 1; day = (newtime->tm_mday); year = (newtime->tm_year) + 1900; } Chapter 8 – Class Relationships

  48. // The getMonth member function accesses // // the month data member of *this. // int Date::getMonth() const { return month; } // The getDay member function accesses // // the day data member of *this. // int Date::getDay() const { return day; } // The getYear member function accesses // // the year data member of *this. // int Date::getYear() const { return year; } // The equality operator for Dates: it verifies // // whether all 3 data members are identical. // bool Date::operator == (const Date &d) const { return ((month == d.month) && (day == d.day) && (year == d.year)); } // The inequality operator for Dates: it // // verifies whether at least one of the // // three data members is not identical. // bool Date::operator != (const Date &d) const { return !(*this == d); } else { struct tm *newtime; long int t; time( &t ); newtime = localtime( &t ); month = (newtime->tm_mon) + 1; day = (newtime->tm_mday); year = (newtime->tm_year) + 1900; } } // The setDate member function uses the // // initializing constructor to set *this // // to the parameterized Date values if // // they represent a legitimate calendar // // date; otherwise, the initializing // // constructor will set *this to today's // // date. // bool Date::setDate(int m, int d, int y) { Date dt(m, d, y); month = dt.getMonth(); day = dt.getDay(); year = dt.getYear(); return ((month == m) && (day == d) && (year == y)); } Chapter 8 – Class Relationships

  49. // The greater-than-or-equal operator for // // Dates: it verifies if the Dates are in // // descending order. // bool Date::operator >= (const Date &d) const { return (d < = *this); } // The output operator for Dates: it // // outputs the Date's data members, // // separated by forward slashes. // ostream& operator << (ostream &file, const Date &d) { file << setw(2) << d.getMonth() << '/' << setw(2) << d.getDay() << '/' << d.getYear(); return file; } // The less-than operator for Dates: it // // verifies how the year values differ. If // // they don't, it verifies how the month // // values differ. If neither the years // // values nor the month values differ, it // // verifies how the day values differ. // bool Date::operator < (const Date &d) const { return ((year < d.year) || ((year==d.year)&&(month<d.month)) || ((year==d.year) && (month==d.month) && (day < d.day))); } // The less-than-or-equal operator for // // Dates: it verifies if the Dates are // // in ascending order. // bool Date::operator <= (const Date &d) const { return ((*this == d) || (*this < d)); } // The greater-than operator for Dates: it // // verifies whether the less-than operator // // holds true if the operands are reversed. // bool Date::operator > (const Date &d) const { return (d < *this); } Note how previously defined operators can be used to implement additional operators Chapter 8 – Class Relationships

  50. Function Templates Just like we did with class templates, we can employ function templates to manipulate distinct classes in a similar fashion. /////////////////////////////////////////////////////////// // Program file: SalesDistribution.cpp // // This program uses reads sales data (dates, times, and // // amounts for various sales) into a trio of arrays. // // Using function templates, it then sorts and outputs // // the data to three different files, based upon type of // // data that was used as the sorting key. // /////////////////////////////////////////////////////////// #include <iostream> #include <iomanip> #include <fstream> #include "date.h" using namespace std; const int MAX_LIST_SIZE = 50; const int STD_OUTPUT_SIZE = 10; void loadData(Date salesDate[], int salesTime[], float salesAmount[], int &listSize); Chapter 8 – Class Relationships

More Related