260 likes | 436 Vues
ACS 168 Problem Solving Using the Computer. Week 13 More on Classes Chapter 8. By Joaquin Vila Prepared by Sally Scott. Tools for Defining ADTs. Defining ADT Operations Friend Functions Implementation of digit_to_int The const Parameter Modifier
E N D
ACS 168Problem Solving Using the Computer Week 13 More on Classes Chapter 8 By Joaquin Vila Prepared by Sally Scott
Tools for Defining ADTs • Defining ADT Operations • Friend Functions • Implementation of digit_to_int • The const Parameter Modifier • Constructors for Automatic Type Conversion • Overloading Unary Operations • Overloading >> and <<
Friend Functions • An ordinary function that is given special access to the private members of a class • NOT a member function of the class • Prototype is listed in the class definition • Keyword friend goes in front of the prototype
Program to demonstrate the function equal. #include <iostream> using namespace std; class DayOfYear { public: DayOfYear(int the_month, int the_day); //Initializes the date according to the arguments. DayOfYear( ); //Initializes the date to January first. void input( ); void output( ); int get_month( ); //Returns the month, 1 for January, 2 for February, etc. int get_day( ); //Returns the day of the month. private: int month; int day; };
This function is defined outside the class. It is NOT a member function, but rather a typical function. bool equal(DayOfYear date1, DayOfYear date2); //Precondition: date1 and date2 have values. //Returns true if date1 and date2 represent the same date, //otherwise returns false. int main( ) { DayOfYear today, bach_birthday(3, 21); cout << "Enter today's date:\n"; today.input( ); cout << "Today's date is "; today.output( ); cout << "J. S. Bach's birthday is "; bach_birthday.output( ); if ( equal(today, bach_birthday)) cout << "Happy Birthday Johann Sebastian!\n"; else cout << "Happy Unbirthday Johann Sebastian!\n"; return 0; } Function call: sends today and bach_birthday
Notice there is no scope resolution operator since it is not a member function of the class. //Function definition for equal bool equal(DayOfYear date1, DayOfYear date2) { return ( date1.get_month( ) == date2.get_month( ) && date1.get_day( ) == date2.get_day( ) ); } //Function definitions for DayOfYear class DayOfYear::DayOfYear(int the_month, int the_day){ month = the_month; day = the_day; } DayOfYear::DayOfYear( ){ month = 1; day = 1; } int DayOfYear::get_month( ){ return month; }
int DayOfYear::get_day( ){ return day; } //Uses iostream: void DayOfYear::input( ){ cout << "Enter the month as a number: "; cin >> month; cout << "Enter the day of the month: "; cin >> day; } //Uses iostream: void DayOfYear::output( ){ cout << "month = " << month << ", day = " << day << endl; }
The equal function must use accessor functions. bool equal(DayOfYear date1, DayOfYear date2){ return ( date1.get_month( ) == date2.get_month( ) && date1.get_day( ) == date2.get_day( ) ); } • Here the function is implemented as a “stand-alone” function. • The problem is, a stand-alone function, defined outside a class, must use accessor functions. • It is possible to allow ordinary functions to have direct access to data members (even though those members are private). • An ordinary function declared as a friend of the class gains the required access.
Friend Functions • An ordinary function declared as a friendof the class gains direct access to private data members without going through member functions. • The class grants friend status by declaring the function with the friend keyword. • When a friend function is defined, you do not use the class name and scope resolution operator as you do with members.
Declaring a function as a friend class DayOfYear Here equal is granted friend status { public: friend bool equal(DayOfYear date1, DayOfYear date2); //Precondition: date1 and date2 have values. //Returns true if date1 and date2 represent the same date; otherwise returns false. DayOfYear(int the_month, int the_day); DayOfYear( ); void input( ); void output( ); int get_month( ); int get_day( ); private: int month; int day; };
Friend vs Regular Function • If the function is listed as a friend in the class definition, the function definition looks like this… bool equal(DayOfYear date1, DayOfYear date2) { return ( date1.month == date2.month && date1.day == date2.day ) } • If the function is NOT listed as a friend in the class definition, the function definition looks like this… bool equal(DayOfYear date1, DayOfYear date2) { return ( date1.get_month( ) == date2.get_month( ) && date1.get_day( ) == date2.get_day( ) ); }
Review of Friend Functions • A friend function of a class is an ordinary (non-member) function that has access granted to private members of a that class. • To make a function a friend of a class • list that function prototype in the class with the keyword friend. • The prototype may be placed in either the public or the private section of the class. • A friend function is NOT a member function. • A friend function is defined and called the same way as any ordinary function. • You do not use the dot operator to call a friend function, and you do not use a class resolution operator in the definition of a friend function.
Consider this code fragment from a mainline function: DayOfYear today;//declaration of an instance of the class cout << “enter today’s date: \n”; today.input(); cout << “There are << (12 - today.get_month()) << “ months left in the year. \n”; • You cannot replace today.get_month() with today.month because month is a private data member. • The function get.month() is a public member function used to access the value stored in the private data member month. • Main does not have direct access because it is not listed as a friend.
Use both Member and Nonmember functions. • Members and friends of a class do similar services for a class. • To clarify whether a given task should be done by a friend or member, consider: • Use a member function if the task being performed by the function involves only one object. • Use a nonmember function if the task being performed involves more than one object. Example: The function equal involves two objects, so we make it a friend. bool equal(DayOfYear date1, DayOfYear date2){ return ( date1.month == date2.month && date1.day == date2.day ); } • Whether member or non-member is not always as simple as this rule suggests. • Clarity and readability is the cardinal rule for this issue.
The const Parameter Modifier • Call-by-value vs. call-by-reference • Call-by-value creates second copy of values • Call-by-value ensures function cannot change parameters • Call-by-reference more efficient for large objects such as classes • For classes use call-by-reference with keyword const • The const modifier allows you to pass a parameter by reference (saving overhead) but guarantees not to change the current value. • The compiler will emit error messages when you compile code that does change the parameter
The const Parameter Modifier Example: Money add(const Money& amount1, const Money& amount2); Here any code written in the implementation of the add function that might change amount1 or amount2 will be marked as an error.
Prototype and Header MUST agree • If you use the const parameter modifier in your prototype in your class, you MUST use the const modifier in exactly the same way in your definition, or you will get errors when you compile your code. Example: class SomeClass { public: void aFunc( const int & aVar, double & bVar); friend int compare(const Date & date1, const Date & date2); }; void SomeClass::aFunc(const int & aVar, double & bVar) { // whatever aFunc does } const in prototype must have const in function definition
Use const with member functions • Use const when member function does not change value of calling object Class SomeClass { void output(ostream & outifle) const; }; void SomeClass::output(ostream & outfile) const { // does output } int main(){ SomeClass ObjA; ObjA.output(outfile); ….. } in application, output function cannot change ObjA
What does const do in each of these cases? const int x = 17; class AClass { public: AClass( ); AClass(int); int aFunc( ) const; int bFunc(const AClass& obj1); private: int i; };
Overloading Operators • C++ provides many operators for manipulating primitive data type such as +, -, *, /, >, <, >>, << • Since C++ does not know how to manipulate our classes, it provides a way to program ADTs with functions that behave “like” built-in types (primitive types). • Overloading operators allows ADTs to use operators such as +, -, stream i/o using << and >> with behavior that the programmer specifies.
Consider adding 2 money objects prototype friend Money operator +(const Money& val1, const Money& val2); Function definition Money operator +(const Money& amt1, const Money& amt2) { Money temp; temp.all_cents = amt1.all_cents + amt2.all_cents; return temp; } in the application you can do this: Money cost(1, 50), tax (0, 15), total; total = cost + tax;
Consider testing for equality by overloading == prototype friend bool operator ==(const Money& amt1, const Money& amt2); Function definition bool operator ==(const Money& amt1, const Money& amt2) { return (amt1.all_cents == amt2.all_cents); } As used in application: Money cost(1, 50), tax(0, 15); …. if (cost == tax) { ……
Rules for overloading operator functions • At least one argument must be of a class type. • Must be a friend to or a member of a class. • Must be an existing operator. • Must keep the operator’s number of arguments. • Must keep the operator’s precedence. • Some operators cannot be overloaded (. ::). • Some must be overloaded in a different way (=) not covered in 168. • Don’t overuse operator overloading. It can lead to unreadable code. • Make sure that the overloaded operator really makes sense and that you won’t be confusing people trying to read your code.
Overloading << and >> • One of the very useful things to overload for most classes. • Must return a reference to the output or input stream. Why? • cout << "I have " << amount << " in my purse.\n "; • ((cout << "I have ") << amount) << " in my purse.\n "; • operator<< (cout, “I have “) returns cout giving… • (cout << amount) << " in my purse.\n "; • operator<< (cout << amount) again returns cout • cout<< " in my purse.\n ";
// returns istream&:istream& operator >> (istream& infile, Money& amount){ //all the necessary code to fetch the amount //from the istream and do some format checking //see input function return infile;}ostream& operator << (ostream& outfile, Money& amount){ //all the necessary code to fetch the amount //from the istream and do some format checking // see output functionreturn outfile;}
Using overloaded << and >> in application Money amount; . . . Stream declarations, file opening, etc infile >> amount; outfile << amount;