67
Chapter 8: Advanced C+ + Topics INHERITANCE VIRTUAL FUNCTIONS CS 240 1 FRIENDS CLASS TEMPLATES OVERLOADED OPERATORS FUNCTION TEMPLATES

Chapter 8: Advanced C++ Topics

  • Upload
    elmo

  • View
    70

  • Download
    2

Embed Size (px)

DESCRIPTION

Chapter 8: Advanced C++ Topics. INHERITANCE. VIRTUAL FUNCTIONS. FRIENDS. CLASS TEMPLATES. OVERLOADED OPERATORS. FUNCTION TEMPLATES. CS 240. 53. Membership Categories. When a class is defined, its members (both data members and member functions) must be categorized. Public Members - PowerPoint PPT Presentation

Citation preview

Page 1: Chapter 8: Advanced C++ Topics

Chapter 8: Advanced C++ Topics

INHERITANCE

VIRTUAL FUNCTIONS

CS 240 1

FRIENDS

CLASS TEMPLATES

OVERLOADED OPERATORS

FUNCTION TEMPLATES

Page 2: Chapter 8: Advanced C++ Topics

CS 240 2

Membership CategoriesWhen a class is defined, its members (both data members and member functions) must be categorized.Public Members

Accessible to all driver programs and other classes that utilize the

class.Protected Members

Accessible only to member functions (and friends) of the class

and its derived classes.Private Members

Accessible only to member functions (and friends) of the class

itself.

Page 3: Chapter 8: Advanced C++ Topics

CS 240 3

class X: public A

X’s public members

X’s protected members

X’s private members

A’s public members

A’s protected members

class Y: protected A

Y’s public members

Y’s protected members

Y’s private members

A’s public members

A’s protected members

class Z: private A

Z’s public members

Z’s private members

Z’s protected members

A’s public members

A’s protected members

InheritanceWhen 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.

class A

A’s public membersA’s protected members

A’s private members

Page 4: Chapter 8: Advanced C++ Topics

CS 240 4

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 simplified, 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_Hclass Account{ public: // Class constructors Account(); Account(float initialBalance); Account(const Account &a);

// Member functions float deposit(float amount); float withdraw(float amount); float getBalance(); Account& operator = (const Account &a);

protected: // Data member float balance;};#define ACCT_H#endif

Page 5: Chapter 8: Advanced C++ Topics

CS 240 5

// Class implementation file: Account.cpp //// The implementations of the member functions of the //// Account class are contained in this program file. //#include "Account.h"

// Default Constructor: Handles the creation of an //// Account with an unspecified initial balance. //Account::Account(){ balance = 0.00F;}

// 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 deposited //// amount to the balance of an Account. //float Account::deposit(float amount){ balance = balance + amount; return balance;}

Page 6: Chapter 8: Advanced C++ Topics

CS 240 6

// Withdraw Member Function: Subtracts a withdrawal amount from the //// balance of an Account, returning the modified balance if there are //// sufficient funds and a negative value if insufficient funds exist. //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 assignment statement. //Account& Account::operator = (const Account &a){ balance = a.balance; return *this;}

Page 7: Chapter 8: Advanced C++ Topics

CS 240 7

/////////////////////////////////////////////////////////////////////// Class definition file: CreditAccount.h //// In this header file, a subclass of the Account class is defined //// to hold information 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 CreditAccount'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“

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

Page 8: Chapter 8: Advanced C++ Topics

CS 240 8

///////////////////////////////////////////////////////////////////// Class implementation file: CreditAccount.cpp //// This program file contains the implementations of the member //// functions of the CreditAccount subclass of the account class. /////////////////////////////////////////////////////////////////////#include "CreditAccount.h"

// The initializing constructor for the CreditAccount class invokes the initializing //// constructor for the Account class, which initializes 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 CreditAccount 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;}

// 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);}

Page 9: Chapter 8: Advanced C++ Topics

CS 240 9

class CreditAccount: public Account

PUBLIC:withdraw

applyFinanceCharge PROTECTED:dailyFinChgRate

depositwithdraw

getBalance= operator

balance

class AccountPUBLIC:deposit

withdrawgetBalance= operator

PROTECTED:balance

Note that CreditAccount has access to both withdraw

functions!

The CreditAccount Derived Class & Its Inheritance from the Account Class

Page 10: Chapter 8: Advanced C++ Topics

CS 240 10

/////////////////////////////////////////////////////////////////////////////// Class definition file: DebitAccount.h //// In this header file, a subclass of the Account class is defined to hold //// information about a DebitAccount. All of the members of the Account //// class are members of the DebitAccount subclass, and the subclass has 3 //// additional members: 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"

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

Page 11: Chapter 8: Advanced C++ Topics

CS 240 11

//////////////////////////////////////////////////////////////////// Class implementation file: DebitAccount.cpp //// This program file contains the implementations of the member //// functions of the DebitAccount subclass of the Account class. ////////////////////////////////////////////////////////////////////#include "DebitAccount.h"

// The initializing constructor for the DebitAccount class invokes the initializing //// constructor for the Account class, which initializes 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);}

Page 12: Chapter 8: Advanced C++ Topics

CS 240 12

class DebitAccount: public AccountPUBLIC:

compoundInterestPROTECTED:dailyIntRatedeposit

withdrawgetBalance= operator balance

class AccountPUBLIC:deposit

withdrawgetBalance= operator

PROTECTED: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...

The DebitAccount Derived Class & Its Inheritance from the Account Class

Page 13: Chapter 8: Advanced C++ Topics

CS 240 13

///////////////////////////////////////////////////////////////////////////////////////// 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

Page 14: Chapter 8: Advanced C++ Topics

CS 240 14

/////////////////////////////////////////////////////////////////////////////// Class implementation file: DebitCreditAccount.cpp //// This program file contains the implementation of the member function //// of the DebitCreditAccount subclass whichinherits from the CreditAccount //// class and has additional characteristics of the DebitAccount class. ///////////////////////////////////////////////////////////////////////////////

#include "DebitCreditAccount.h"

// The DebitCreditAccount initializing constructor inherits from //// the CreditAccount initializing constructor, with the addition //// of an initializing assignment 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);}

Page 15: Chapter 8: Advanced C++ Topics

CS 240 15

class DebitCreditAccount:public CreditAccount

PUBLIC:compoundInterest

PROTECTED:dailyIntRate

withdrawapplyFinanceCharge

dailyFinChgRate

depositwithdraw

getBalance= operator

balance

class CreditAccount:public Account

PUBLIC:withdraw

applyFinanceCharge

PROTECTED:dailyFinChgRate

depositwithdraw

getBalance= operator

balance

class Account

PUBLIC:deposit

withdrawgetBalance= operator

PROTECTED:balance

The DebitCreditAccount Derived Class & Its Inheritance from the CreditAccount & Account Classes

Page 16: Chapter 8: Advanced C++ Topics

CS 240 16

// Program file: DebitCreditDriver.cpp //// This program tests various aspects of the Account class and its three //// subclasses: DebitAccount, CreditAccount, and DebitCreditAccount. //#include <iostream>#include <iomanip>#include <fstream>#include "DebitAccount.h"#include "CreditAccount.h"#include "DebitCreditAccount.h"using namespace std;

void printBalance(const char name[], Account &a);

// The main function sets up three variables, one of type DebitAccount, one of type //// CreditAccount, 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 DebitAccount 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 half from the DebitAccount. float transaction;

Page 17: Chapter 8: Advanced C++ Topics

CS 240 17

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);

// 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; }

Page 18: Chapter 8: Advanced C++ Topics

CS 240 18

// 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;}

Page 19: Chapter 8: Advanced C++ Topics

CS 240 19

// 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

Page 20: Chapter 8: Advanced C++ Topics

CS 240 20

// Class declaration file: queue.h// Array implementation of the queue ADT.#ifndef QUEUE_H#include <fstream>using namespace std;

typedef int elementType;const int 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

Inheritance Example #2: Weeding Queues

New Queue Functionality:• Enqueue an entire input

file• Queue output operator

Page 21: Chapter 8: Advanced C++ Topics

CS 240 21

// 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]; }}

// 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;}

// isFull function; returns bool //// indicating if *this is a full //// Queue (wrt the array). //bool Queue:: isFull() const{ return (length == MAX_QUEUE_SIZE); }

Page 22: Chapter 8: Advanced C++ Topics

CS 240 22

// 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;}

Page 23: Chapter 8: Advanced C++ Topics

CS 240 23

// 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 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 is 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 WeedingQueue), and then// the new item is inserted at the rear// of the WeedingQueue.

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++;}

Page 24: Chapter 8: Advanced C++ Topics

CS 240 24

// Program file: WeedingQueueDriver.cpp //// This program tests the WeedingQueue //// class by inserting 50 values via the //// inputEnqueue member function. //

#include <iostream>#include <fstream>#include "WeedingQueue.h"using namespace std;

// 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 2188 35 91 17 53 28 59 82 36 7216 38 78 92 73 16 83 95 19 6646 20 39 65 48 27 63 49 14 8462 31 93 38 77 80 11 98 67 45

Contents of queueData.txt:

Resulting Output:

Why did this fail?

Page 25: Chapter 8: Advanced C++ Topics

CS 240 25

Virtual Functions & Late BindingThe 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

(which doesn’t handle overflow), not the enqueue

member function of the WeedingQueue subclass

(which does handle overflow)!

Page 26: Chapter 8: Advanced C++ Topics

CS 240 26

// 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; virtual 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 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!

Page 27: Chapter 8: Advanced C++ Topics

CS 240 27

Generally, follow these guidelines when deciding whether to make a member function virtual: Make the functions of the base

class virtual, so they can be overridden. C++ doesn’t support virtual constructors. (When an object is declared, a Virtual Method Table is created, with pointers to all of its virtual functions. Since the VMT is created as part of the constructor process, the constructor itself cannot be one of the virtual methods.) Always make destructors virtual. (This ensures that the derived class destructor is called before the base class destructor, avoiding memory leaks.)

Q = Instance of Queue

WQ = Instance of

WeedingQueue

VMT for QDefault ConstructorCopy Constructor

isEmpty Functionenqueue Function

inputEnqueue Function

Input Operator

VMT for WQDefault ConstructorCopy Constructor

isEmpty Functionenqueue Function

inputEnqueue Function

Input Operator

Code forDefault Constructor

Code forCopy Constructor

Code forisEmpty Function

Code forenqueue Function

Code forinputEnqueue

FunctionCode for

Input Operator

Code forenqueue Function

Page 28: Chapter 8: Advanced C++ Topics

CS 240 28

FriendsThere are occasions when it is necessary to give a class or function access to the private members of another class.On those occasions, the class or function that needs that access may be declared a friend of the class that’s giving access.Examples:• I/O operators• Binary operators• Dependent classes

Page 29: Chapter 8: Advanced C++ Topics

CS 240 29

Example: Affine Transformations// Class Definition File: Matrix.h //// The Mtrx class uses homogeneous //// coordinates to represent 2D affine //// transformations, while the Vctr //// class uses homogeneous coordinates //// to represent 2D points. //

#ifndef MATRIX_H#include <fstream>using namespace std;

class Mtrx;

class Vctr{ public: // Constructors Vctr(); Vctr(const Vctr &v); Vctr(const float &x, const float &y);

private: // Data Members float coord[3];

// Friends friend ostream& operator << (ostream &os, const Vctr &v); friend Vctr operator * (const Mtrx &m, const Vctr &v); friend class Mtrx; };

class Mtrx{ public: // Constructors Mtrx(); Mtrx(const Mtrx &m); Mtrx(const int &angle); Mtrx(const float &scaleFactor); Mtrx(const float &translateX, const float &translateY);

private: // Data Members Vctr column[3];

// Friends friend Vctr operator * (const Mtrx &m, const Vctr &v);};

#define MATRIX_H#endifGives the output

operator access to the coord data

member and all of the constructors

Gives the multiplication

operator access to the coord data

member and all of the constructors

Gives the entire Matrix class access to

the coord data member and all of the constructors

Gives the multiplication

operator access to the column data

member and all of the Matrix

constructors

Page 30: Chapter 8: Advanced C++ Topics

CS 240 30

// Class Implementation File: Mtrx.cpp#include <math.h>#include "Matrix.h"const float PI = 3.14159F;

// Vctr default constructor: Sets up null Vctr (weight factor 1).Vctr::Vctr(){ coord[0] = coord[1] = 0; coord[2] = 1;}

// Vctr copy constructor: Duplicates the parameterized Vctr.Vctr::Vctr(const Vctr &v){ int i; for (i = 0; i <= 2; i++) coord[i] = v.coord[i];}

// Vctr initializing constructor: Sets up a weight-1// Vctr with the parameterized x and y coordinates.Vctr::Vctr(const float &x, const float &y){ coord[0] = x; coord[1] = y; coord[2] = 1;}

// Vctr output operatorostream& operator << (ostream &os, const Vctr &v){ if (v.coord[2] == 0) os << "(" << 0.0 << "," << 0.0 << ")"; else os << "(" << v.coord[0]/v.coord[2] << "," << v.coord[1]/v.coord[2] << ")"; return os;}

Page 31: Chapter 8: Advanced C++ Topics

CS 240 31

// Mtrx default constructor: Sets up identity Mtrx.Mtrx::Mtrx(){ int i,j; for (i = 0; i <= 2; i++) for (j = 0; j <= 2; j++) column[i].coord[j] = (i == j) ? 1.0F : 0.0F; return;}

// Mtrx copy constructor: Duplicates each Mtrx slot.Mtrx::Mtrx(const Mtrx &m){ int i, j; for (i = 0; i <= 2; i++) for (j = 0; j <= 2; j++) column[i].coord[j] = m.column[i].coord[j]; return;}

// Mtrx initializing constructor: sets up Mtrx for rotating the parameterized # of degrees.Mtrx::Mtrx(const int &angle){ float floatAngle = PI * angle / 180.0F; column[0].coord[0] = column[1].coord[1] = cos(floatAngle); column[0].coord[1] = sin(floatAngle); column[1].coord[0] = -sin(floatAngle); column[0].coord[2] = column[2].coord[0] = column[1].coord[2] = column[2].coord[1] = 0.0F; column[2].coord[2] = 1.0F; return;}

Page 32: Chapter 8: Advanced C++ Topics

CS 240 32

// Mtrx initializing constructor: sets up Mtrx for scaling by the parameterized factor.Mtrx::Mtrx(const float &scaleFactor){ column[0].coord[0] = column[1].coord[1] = scaleFactor; column[2].coord[2] = 1.0F; column[0].coord[1] = column[0].coord[2] = column[1].coord[0] = column[1].coord[2] = column[2].coord[0] = column[2].coord[1] = 0.0; return;}

// Mtrx initializing constructor: sets up Mtrx for translating in the parameterized direction.Mtrx::Mtrx(const float &translateX, const float &translateY){ column[0].coord[0] = column[1].coord[1] = column[2].coord[2] = 1.0F; column[0].coord[1] = column[1].coord[0] = column[0].coord[2] = column[1].coord[2] = 0.0F; column[2].coord[0] = translateX; column[2].coord[1] = translateY; return;}

// Multiplication operator to apply a transformation// Mtrx to a Vctr and obtain the transformed Vctr.Vctr operator * (const Mtrx &m, const Vctr &v){ Vctr result; int i, j; for (i = 0; i <= 2; i++) { result.coord[i] = 0.0F; for (j = 0; j <= 2; j++) result.coord[i] += m.column[j].coord[i] * v.coord[j]; } return result;}

Page 33: Chapter 8: Advanced C++ Topics

CS 240 33

// Driver file: MatrixDriver.cpp// This program queries the user to specify two 2D affine// transformations (scaling, translation, rotation) and a// pair of 2D coordinates. It then compares what happens// when the transformations are applied to the coordinates// in either order (specifically, whether the same result// is produced).

#include <iostream>#include <string>#include "Matrix.h"using namespace std;

Mtrx retrieveTransformation(string &label);Vctr retrieveVector();

void main(){ string headerA = "Transformation A: "; string headerB = "Transformation B: "; Mtrx matA = retrieveTransformation(headerA); Mtrx matB = retrieveTransformation(headerB); Vctr v = retrieveVector(); Vctr ABv = matA * (matB * v); Vctr BAv = matB * (matA * v);

cout << endl << headerA << endl << headerB << endl << endl; cout.setf(ios::fixed); cout.setf(ios::showpoint); cout.precision(2); cout << "Transform by A, then by B: " << BAv << endl; cout << "Transform by B, then by A: " << ABv << endl; cout << endl << "Enter anything to exit: "; cin >> headerA;}

Page 34: Chapter 8: Advanced C++ Topics

CS 240 34

// The retrieve Transformation function queries the// user regarding a transformation's type and parameters,// creates the corresponding transformation matrix,// alters the parameterized label to indicate the// type of transformation, and then returns the matrix.Mtrx retrieveTransformation(string &label){ char transformType; cout << "Specify which type of affine transformation" << endl << "(R: Rotation, S: Scaling, T: Translation)" << endl << "you want to use for " << label; cin >> transformType; transformType = toupper(transformType); while (string("RST").find(transformType) < 0) { cout << "Try again (RST): "; cin >> transformType; transformType = toupper(transformType); } cout << endl;

switch (transformType) { case 'R': { int nbrDegrees; cout << "Enter the number of degrees for the rotation: "; cin >> nbrDegrees; cout << endl; label = label + "Rotation"; Mtrx resultMtrx(nbrDegrees); return resultMtrx; }

Page 35: Chapter 8: Advanced C++ Topics

CS 240 35

case 'S': { float scale; cout << "Enter the scaling factor: "; cin >> scale; cout << endl; label = label + "Scaling"; Mtrx resultMtrx(scale); return resultMtrx; } default: { float x, y; cout << "Enter the translation amount in the x-direction: "; cin >> x; cout << "Enter the translation amount in the y-direction: "; cin >> y; cout << endl; label = label + "Translation"; Mtrx resultMtrx(x,y); return resultMtrx; } }}

// The retrieveVector function queries the user regarding a// 2D point, which is converted into a Vector and returned.Vctr retrieveVector(){ float x, y; cout << "Specify the x-coordinate of the point you plan to transform: "; cin >> x; cout << "Specify the y-coordinate of the point you plan to transform: "; cin >> y; cout << endl; return Vctr(x,y);}

Page 36: Chapter 8: Advanced C++ Topics

CS 240 36

Page 37: Chapter 8: Advanced C++ Topics

CS 240 37

TemplatesC++ provides a mechanism for avoiding redundancy in the creation of classes and functions.

temp

Swap Function for

double

temp

Swap Function for

float

temp

Swap Function for

inttemp

Swap Function for

stack

temp

Swap Function for

queue

temp

Swap Function for

bool

temp

Swap Function for

chartemp

Swap Function for

string temp

Swap Function for

matrix

Linked List Class for int

Linked List Class for bankAcct

Linked List Class for double

Linked List Class for long

int

Linked List Class for bool

Linked List Class for queue

Linked List Class for matrix

Linked List Class for float

Linked List Class for nodePtr

Linked List Class for

stack

Linked List Class for char

Linked List Class for

string

Page 38: Chapter 8: Advanced C++ Topics

CS 240 38

Class Template Example: Two-Field Label

field1

field2indent2

indent1

topGap

midGapheight

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 classes of field1 and field2 both 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.

Page 39: Chapter 8: Advanced C++ Topics

CS 240 39

Definition & Implementation of Two-Field Label Class////////////////////////////////////////////////////// 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>using namespace std;

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);

// 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;}

template <typename E1, typename E2> 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;};

Page 40: Chapter 8: Advanced C++ Topics

CS 240 40

/*** 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;}

// Initializing constructor: Sets *this to //// have the parameterized gap sizes and //// indentations, 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 //// indentations, 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;}

// 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();}

Page 41: Chapter 8: Advanced C++ Topics

CS 240 41

// The output operator is overloaded to //// appropriately format the two-field label. //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

Page 42: Chapter 8: Advanced C++ Topics

CS 240 42

New Person Class For Use With The Two-Field Label Class ///////////////////////////////////////////////////////////////

// Class definition 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

Page 43: Chapter 8: Advanced C++ Topics

CS 240 43

/////////////////////////////////////////////// Class implementation file: Person.cpp //// //// This program file contains the actual //// implementations of the member functions //// of the person class defined in the //// Person.h header file. ///////////////////////////////////////////////

#include "Person.h"#include <string>

using namespace std;

// The default constructor sets the three //// data members of *this to empty strings. //person::person(){ fullName = firstAddressLine = secondAddressLine = "";}

// The copy constructor sets the three data //// members of *this to the corresponding data //// member values of the parameterized person. //person::person(const person &p){ fullName = p.fullName; firstAddressLine = p.firstAddressLine; secondAddressLine = p.secondAddressLine;}

// 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; }}

Page 44: Chapter 8: Advanced C++ Topics

CS 240 44

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);

// 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;}

Page 45: Chapter 8: Advanced C++ Topics

CS 240 45

// 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]; char addr[MAX_STRING_SIZE]; char 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;}

Page 46: Chapter 8: Advanced C++ Topics

CS 240 46

// The createLabels function reads all of the person data from the //// personFile input file, and generates a mailing label to each //// person, with the source parameter as the return address. Each //// label is then output to the labelFile output file. //void createLabels(person source, ifstream &personFile, ofstream &labelFile){ twoFieldLabel<person, person> label; person destination; char name[MAX_STRING_SIZE]; char addr[MAX_STRING_SIZE]; char 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); }}

Page 47: Chapter 8: Advanced C++ Topics

CS 240 47

// 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;}

Fred FlintstoneOne Million BC LaneBedrock CA 00000

Marge Simpson417 Evergreen StreetSpringfield IL 36963

Ren Hoek1237 Stimpy AvenueMudskipper WI 86420

Scooby Doo666 Shaggy DriveAmityville MA 75421

...

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 ...

addresses.txt

LBL.txt

Page 48: Chapter 8: Advanced C++ Topics

CS 240 48

New LabelString Class For Use With The Two-Field Label Class ////////////////////////////////////////////////

// Class definition file: LabelString.h //// //// This program file contains the definitions //// of the members of the labelString 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

Page 49: Chapter 8: Advanced C++ Topics

CS 240 49

////////////////////////////////////////////////// Class implementation file: LabelString.cpp //// //// This program file contains the actual //// implementations 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 labelString's text data member //// to the parameterized character array. //labelString::labelString(const char str[]){ text = str;}

// This initializing constructor sets //// the labelString's text data member //// to the parameterized string value. //labelString::labelString(const string &str){ text = str;}

// The copy constructor sets the *this //// label String's text data member to //// the parameterized 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;}

Page 50: Chapter 8: Advanced C++ Topics

CS 240 50

Driver Using A Two-Field Label With One Person Field And One LabelString Field////////////////////////////////////////////////// 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);

// The main function opens the I/O files, re- //// trieves 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 containing //// 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;}

Page 51: Chapter 8: Advanced C++ Topics

CS 240 51

// The generateLabelFile function reads the //// person data from the parameterized input //// file, and 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);

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;}

Page 52: Chapter 8: Advanced C++ Topics

CS 240 52

223-66-9032Elroy JetsonDept. 63BMailstop 5031

221-80-9076Lisa SimpsonDept. 12CMailstop 1654

177-72-7874Harley QuinnDept. 33BMailstop 920

223-43-8190Scrappy DooDept. 71AMailstop 1902

222-22-2222Harvey DentDept. 22BMailstop 2222

220-53-8068Wile E. CoyoteDept. 43DMailstop 3117

221-91-0253Maggie SimpsonDept. 12CMailstop 1655

127-55-7293Pebbles FlintstoneDept. 33AMailstop 2825

637-44-1099Daisy DuckDept. 18CMailstop 3101

634-29-2906Minnie MouseDept. 18BMailstop 3096

224-64-1457Betty RubbleDept. 41DMailstop 1782

772-25-2765Quick Draw McGrawDept. 86XMailstop 3210

223-66-9032

Elroy JetsonDept. 63BMailstop 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 DentDept. 22BMailstop 2222

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 220-53-8068

Wile E. Coyote Dept. 43D Mailstop 3117

++++++++++++++++++++++++++++++++++++++

employees.txt FLDR.txt

Page 53: Chapter 8: Advanced C++ Topics

CS 240 53

New Monetary Class For Use With 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 parameterized value. //monetary::monetary(const float &amt){ amount = amt;}

// The copy constructor sets the monetary amount //// to that of the parameterized monetary value. //monetary::monetary(const monetary &m){ amount = m.amount;}

Page 54: Chapter 8: Advanced C++ Topics

CS 240 54

// 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;}

Page 55: Chapter 8: Advanced C++ Topics

CS 240 55

Driver Using A Two-Field Label With One LabelString Field And One Monetary Field//////////////////////////////////////

// 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);

// 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;}

Page 56: Chapter 8: Advanced C++ Topics

CS 240 56

// Function queryUser queries the user for //// the inventory number, price, amount //// 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;}

Page 57: Chapter 8: Advanced C++ Topics

CS 240 57

// 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;}

XYZ-123

$14.94

***************XYZ-123

$14.94

***************XYZ-123

$14.94

***************

ABC-789

$511.07

***************ABC-789

$511.07

***************ABC-789

$511.07

***************ABC-789

$511.07

***************ABC-789

$511.07

***************

XYZ.txtABC.txt

Page 58: Chapter 8: Advanced C++ Topics

CS 240 58

Overloaded OperatorsAs we’ve seen, when we create a new class, we can overload many 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. //////////////////////////////////////////////

#include <fstream>using namespace std;

#ifndef DATE_H

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;

// Overloaded Equality & Inequality Operators 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;

// Overloaded Output Operator friend ostream& operator << (ostream &file, const Date &d);

private: int month; int day; int year;};

#define DATE_H#endif

Page 59: Chapter 8: Advanced C++ Topics

CS 240 59

////////////////////////////////////////////// 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 ctime). //Date::Date(){ struct tm newtime; time_t t; time( &t ); errno_t err = localtime_s( &newtime, &t ); month = (newtime.tm_mon) + 1; day = (newtime.tm_mday); year = (newtime.tm_year) + 1900;}

Page 60: Chapter 8: Advanced C++ Topics

CS 240 60

// The initializing constructor for the Date class initializes *this with the //// parameterized 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 ctime). //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; } else { struct tm newtime; time_t t; time( &t ); errno_t err = localtime_s( &newtime, &t ); month = (newtime.tm_mon) + 1; day = (newtime.tm_mday); year = (newtime.tm_year) + 1900; }}

Page 61: Chapter 8: Advanced C++ Topics

CS 240 61

// 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));}

// 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;}

Page 62: Chapter 8: Advanced C++ Topics

CS 240 62

// The greater-than operator for Dates: it //// merely verifies whether the less-than //// operator holds true if the operands are //// reversed. //bool Date::operator > (const Date &d) const{ return (d < *this);}

// 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 (*this <= d);}

// 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 equality operator for Dates: it verifies //// whether all three 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);}

// The less-than operator for Dates: it verifies //// how the year values differ. If they don't, then //// 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));}

Page 63: Chapter 8: Advanced C++ Topics

CS 240 63

Function TemplatesJust 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);

template<class E>void showDistribution(char filename[], E list[], int size, char label[]);

template<class E>void selectionSort(E list[], int size);

template<class E>void swapper(E &valueA, E &valueB);

template<class E>int indexOfSmallest(E list[], int startIndex, int stopIndex);

Page 64: Chapter 8: Advanced C++ Topics

CS 240 64

// The main function supervises the input and the //// sorting and output operations that transpire. //void main(){ Date dateList[MAX_LIST_SIZE]; int timeList[MAX_LIST_SIZE]; float amountList[MAX_LIST_SIZE]; int inputSize; ofstream outputFile; loadData(dateList, timeList, amountList, inputSize); showDistribution("DistByDate.txt", dateList, inputSize, "date"); showDistribution("DistByTime.txt", timeList, inputSize, "time"); showDistribution("DistByAmnt.txt", amountList, inputSize, "amount"); return;}

// The loadDate function loads the three arrays from a hard-coded input file. //// Data is assumed to be in the form: M D Y T A, where M is an integer month, //// D is an integer day, Y is an integer year, T is an integer time (military), //// and A is a floating-point amount (dollars & cents). //void loadData(Date salesDate[], int salesTime[], float salesAmount[], int &listSize){ int month, day, year; ifstream inputFile; inputFile.open("sales.txt"); listSize = 0; inputFile >> month; while (!inputFile.eof()) { inputFile >> day >> year; salesDate[listSize] = Date(month, day, year); inputFile >> salesTime[listSize]; inputFile >> salesAmount[listSize]; listSize++; inputFile >> month; } inputFile.close(); return;}

Page 65: Chapter 8: Advanced C++ Topics

CS 240 65

// The showDistribution function template opens the output file with //// the parameterized name, outputs a header (using the parameterized //// label), and then sorts and outputs the parameterized list. //template<class E>void showDistribution(char filename[], E list[], int size, char label[]){ ofstream file; file.open(filename); file.setf(ios::fixed); file.precision(2); file << "Sales Distribution" << endl << " (by " << label << ")" << endl; selectionSort(list, size); for (int i = 0; i < size; i++) file << setw(STD_OUTPUT_SIZE) << list[i] << endl; file.close();}

// The selectionSort function template sorts the parameterized list //// using the simple selection sort algorithm (i.e., repeatedly locate //// the smallest list element that has not yet been placed in its proper //// position, and swap it with the earliest unsorted element in the list. //template<class E>void selectionSort(E list[], int size){ int smallestIndex; for (int i = 0; i < size - 1; i++) { smallestIndex = indexOfSmallest(list, i, size - 1); if (i != smallestIndex) swapper(list[i], list[smallestIndex]); }}

Page 66: Chapter 8: Advanced C++ Topics

CS 240 66

// The swapper function template merely swaps //// the values of the two parameters. It //// assumes that the assignment operator is //// defined for the E class. //template<class E>void swapper(E &valueA, E &valueB){ E temp = valueA; valueA = valueB; valueB = temp; return;}

// The indexOfSmallest function template determines //// the index (between the two parameterized indices) //// of the smallest value in the parameterized list. //// It assumes that the less-than operator (<) has //// been defined for the class E. //template<class E>int indexOfSmallest(E list[], int startIndex, int stopIndex){ int smallestIndex = startIndex; for (int i = startIndex + 1; i <= stopIndex; i++) if (list[i] < list[smallestIndex]) smallestIndex = i; return smallestIndex;}

Page 67: Chapter 8: Advanced C++ Topics

CS 240 67

7 20 2009 1435 25.75 6 11 2008 922 216.63 1 9 2010 1114 75.80 4 20 2008 2012 407.4812 30 2008 1457 783.99 5 9 2010 1303 16.25 9 13 2010 1638 56.7310 16 2009 859 277.11 9 13 2010 1737 89.04 5 17 2009 1035 313.36 3 22 2008 1644 124.07 9 13 2010 905 90.15 7 20 2010 1833 35.12 6 11 2008 958 126.84 4 9 2010 1239 9.3611 20 2009 1904 15.3512 11 2008 921 117.77 8 9 2010 1706 23.92 9 11 2008 845 277.11 2 29 2010 2107 166.88

Sales Distribution (by date) 3/22/2008 4/20/2008 6/11/2008 6/11/2008 9/11/200812/11/200812/30/2008 5/17/2009 7/20/200910/16/200911/20/2009 1/ 9/2010 2/29/2010 4/ 9/2010 5/ 9/2010 7/20/2010 8/ 9/2010 9/13/2010 9/13/2010 9/13/2010

Sales Distribution (by time) 845 859 905 921 922 958 1035 1114 1239 1303 1435 1457 1638 1644 1706 1737 1833 1904 2012 2107

Sales Distribution (by amount) 9.36 15.35 16.25 23.92 25.75 35.12 56.73 75.80 89.04 90.15 117.77 124.07 126.84 166.88 216.63 277.11 277.11 313.36 407.48 783.99