CS 228 meeting -*- Outline -*- * overloading in C++ (HR 3.5-3.6, DD 8) ** a problem with binary member functions --------------------------------- BINARY FUNCTION PROBLEMS Check whether two accounts have the same balance. // Account_equal.C #include "Account.h" #include "pretend_bool.h" bool Equal(Account a1, Account a2) // POST: FCTVAL is true iff // the balances of a1 and a2 are // exactly equal { } --------------------------------- fill in with return a1.Dollars() == a2.Dollars(); This is the right idea, but we might worry that we are only comparing approximations, and we're comparing doubles for equality, which is bad (dangereous) It's also a bit inefficient, as we convert to double, divide by 100, and make 2 function calls... Q: what else can we do as a client? can't access the data members ** solutions (3.5) *** use a member function ---------------------------------- USING A MEMBER FUNCTION // Account.h #ifndef Account_h #define Account_h 1 #include "pretend_bool.h" class Account { // ABSTRACTLY: some number of dollars // CLASSINV: the balance is not negative public: Account(); // default constructor // MODIFIES: self // POST: balance of self is zero // ... bool Equal(Account a2) const; // POST: FCTVAL is true iff // the balances of self and a2 are // exactly equal #include "Account.pri" }; #endif ----------------------------------- That's the spec. ----------------------------------- IMPLEMENTATION OF MEMBER FUNCTION // Account.C #include "Account.h" Account::Account() { numCents = 0; } //... bool Account::Equal(Account a2) const { } ----------------------------------- fill the code in above: return numCents == a2.numCents; Annoying lack of symmetry in this code. ----------------------------- CLIENT CODE WITH MEMBER FUNCTION // AccountClient.C #include #include "Account.h" int main() { Account acct1; acct1.Deposit(500); Account acct2(1700); if ( acct1.Equal(acct2) ) { cout << "they're equal\n"; } else { cout << "they're not\n"; } } ----------------------------- Annoying notation isn't symmetric, *** use a friend function ------------------------------ PROBLEM How to get symmetric client code? And still have efficiency of private access to data members? FRIENDSHIP A class can grant private access to named functions and classes, such functions and classes are called *friends*. ------------------------------ "Your friends can see your private parts" (:->) ------------------------------- GRANTING FRIENDSHIP // Account.pri private: int numCents; // ABSTRACTION MAP: dollar balance // is numCents / 100. friend bool Equal(Account a1, Account a2); and take Equal out of Account.h... ------------------------------- Why should the client care about it? it's an implementation detail. Notice: no const here: it's not a member function, and const only works for member functions ------------------------------ IMPLEMENTING Equal AS A FRIEND FUNCTION // Account_equal.C #include "Account.h" #include "pretend_bool.h" bool Equal(Account a1, Account a2) // POST: FCTVAL is true iff // the balances of a1 and a2 are // exactly equal { } -------------------------------- fill in the above with return a1.numCents == a2.numCents; note that in contrast to HR, only write the spec here, not at the point of the friendship grant. ----------------------------- CLIENT CODE WITH FRIEND FUNCTION // AccountClient.C #include #include "Account.h" #include "Account_equal.h" int main() { Account acct1; acct1.Deposit(500); Account acct2(1700); if ( Equal(acct1, acct2) ) { cout << "they're equal\n"; } else { cout << "they're not\n"; } } ----------------------------- ** overloading (3.6) would still like the notation ... ------------------------------- PROBLEM Want to write if ( acct1 == acct2 ) { //... } SOLUTION: OPERATOR OVERLOADING Change name from Equal to operator == Can also overload +, -, *, /, <<, >>, ... ------------------------------- *** friend overload ------------------------------- GRANTING FRIENDSHIP TO OVERLOAD // Account.pri private: int numCents; // ABSTRACTION MAP: dollar balance // is numCents / 100. friend bool operator == (Account a1, Account a2); ------------------------------- ------------------------------ IMPLEMENTING == AS A FRIEND FUNCTION // Account_equal.C #include "Account.h" #include "pretend_bool.h" bool operator ==(Account a1, Account a2) // POST: FCTVAL is true iff // the balances of a1 and a2 are // exactly equal { return a1.numCents == a2.numCents; } -------------------------------- *** using a member function ---------------------------------- USING A MEMBER FUNCTION // Account.h #ifndef Account_h #define Account_h 1 #include "pretend_bool.h" class Account { // ABSTRACTLY: some number of dollars // CLASSINV: the balance is not negative public: Account(); // default constructor // MODIFIES: self // POST: balance of self is zero // ... bool operator ==(Account a2) const; // POST: FCTVAL is true iff // the balances of self and a2 are // exactly equal #include "Account.pri" }; #endif ----------------------------------- take it out of the Account.pri file That's the spec. ----------------------------------- IMPLEMENTATION OF MEMBER FUNCTION bool Account::operator == (Account a2) const { return numCents == a2.numCents; } CLIENT CODE if ( acct1 == acct2 ) { //... } ----------------------------------- the client code in this case is same in either case. See HR book for details. ** overloading the "put to" (output) operator <<, see DD pp. 448-449 a bit advanced, with the references, but useful... ------------------------------ OVERLOADING operator << Suppose we want to write the following: // AccountClient.C #include "Account.h" int main() { Account acct(300); cout << acct << endl; } ------------------------------- note parenthesization of above means (cout << acct) << endl; so operator << has to return a ostream. ------------------------------- // Account.h #ifndef Account_h #define Account_h 1 #include class Account { // ... }; extern ostream & operator << (ostream & out, const Account & a); // PRE: out is in a good state // MODIFIES: out // POST: a printed form of a // is added to out ------------------------------- Then have to implement it. ------------------------------- // Account.C #include "Account.h" #include "iomanip.h" // ... ostream & operator << (ostream & out, const Account & a) { out << "$"; out.setf(ios::showpoint); out.setf(ios::fixed, ios::floatfield); out.precision(2); out << a.Dollars(); return out; } ------------------------------- ** additional example (if time) might want to look at the fraction module from the book...