Upload
daniella-opal-freeman
View
215
Download
0
Embed Size (px)
Citation preview
Chapter 11
Friends and Overloaded Operators
Introduction to function equal// Date.h#ifndef _DATE_H_#define _DATE_H_
class CDate{public:
CDate(); // default constructorCDate(int m, int d, int y); // parameterized constructorCDate(const CDate& aDay); // copying constructor~CDate(); // destructor
int getMonth(); // accessorint getDay(); // accessorvoid setMonth(int m); // mutatorvoid setDay(int d); // mutator
void display(); // a member function
int year;private:
int month;int day;
};#endif
#include “Date.h”
bool equal (CDate day1, CDate day2);void main (){
CDate myBD(3, 31, 1996), yourBD;cout << "Enter your birthday as month, day, year ”; int m, d;cin >> m >> d >> yourBD.year;yourBD.setMonth(m);yourBD.setDay(d);if (equal(myBD, yourBD))
cout << “Let’s celebrate together.”; }
bool equal (CDate day1, CDate day2){
return (day1.getMonth() == day2.getMonth()) &&day1. getDay() == day2. getDay()) &&day1.year == day2.year);
}
Function equal
• prototype of equal is outside of the class.• equal is a nonmember function of the class
requiring 2 objects• To access the members, it must still use member
accessor functions since the attributes are private and can only be accessed by public member functions.
• It does not change the data members. Only member functions or friend functions should be able to alter private members.
Friend functions• A non-member function that has membership
privileges.• Notes:
– Prototype goes in public section with keyword friend in front
– Function call is like a regular function - does not use dot operator
– When to use:• Functions between two members of the same class
Friend function equal// Date.h#ifndef _DATE_H_#define _DATE_H_
class CDate{public:
CDate(); // default constructorCDate(int m, int d, int y); // parameterized constructorCDate(const CDate& aDay); // copying constructor~CDate(); // destructor
friend bool equal(CDate day1, CDate day2);int getMonth(); // accessorint getDay(); // accessorvoid setMonth(int m); // mutatorvoid setDay(int d); // mutator
void display(); // a member function
int year;private:
int month;int day;
};#endif
#include “Date.h”
void main (){
CDate myBD(3, 31, 1996), yourBD;cout << "Enter your birthday as month, day, year ”; int m, d;cin >> m >> d >> yourBD.year;yourBD.setMonth(m);yourBD.setDay(d);if (equal(myBD, yourBD))
cout << “Let’s celebrate together.”; }
bool equal (CDate day1, CDate day2){
return (day1.month == day2.month) &&day1. day == day2. day) &&day1.year == day2.year);
}
The const Parameter Modifier• It is more efficient to call by reference than by value.
– value: passes in a copy of the variable. If the variable is large or structured this takes up extra space.
– reference: passes in the address only but it does allow changes
• Solution: call by reference but put const modifier which prevents change - generates error message.
• Used for classes, structs and arrays. • const used after function prototype and definition prevents
function from changing calling objects - generates error message. – void output (ostream& outs) const;
• If the function prototype and it’s definition do not both have the const modifier, then you will get a linkage error.
• Accessor and output functions should be const.
Friend function equal with const// Date.h#ifndef _DATE_H_#define _DATE_H_
class CDate{public:
CDate(); // default constructorCDate(int m, int d, int y); // parameterized constructorCDate(const CDate& aDay); // copying constructor~CDate(); // destructor
friend bool equal(const CDate& day1, const CDate& day2);int getMonth(); // accessorint getDay(); // accessorvoid setMonth(int m); // mutatorvoid setDay(int d); // mutator
void display(); // a member function
int year;private:
int month;int day;
};#endif
#include “Date.h”
void main (){
CDate myBD(3, 31, 1996), yourBD;cout << "Enter your birthday as month, day, year ”; int m, d;cin >> m >> d >> yourBD.year;yourBD.setMonth(m);yourBD.setDay(d);if (equal(myBD, yourBD))
cout << “Let’s celebrate together.”; }
bool equal (const CDate& day1, const CDate& day2){
return (day1.month == day2.month) &&day1. day == day2. day) &&day1.year == day2.year);
}
Overloading Operator
• Changing the definition of an operator from the default operation to a new operation.
• Allows for smooth functionality in ADT’s.
Overloading Operator (example)
• Want to write as:if (myBD == yourBD) // syntax error
• Current operation == does not take operands typed CDate.
• Need to redefine == operator to take 2 CDate objects.
• Function definition is exactly the same as equal.• Declared as a friend function.• Has the keyword operator.
Friend function equal with const// Date.h#ifndef _DATE_H_#define _DATE_H_
class CDate{public:
CDate(); // default constructorCDate(int m, int d, int y); // parameterized constructorCDate(const CDate& aDay); // copying constructor~CDate(); // destructor
friend bool operator ==(const CDate& day1, const CDate& day2);int getMonth(); // accessorint getDay(); // accessorvoid setMonth(int m); // mutatorvoid setDay(int d); // mutator
void display(); // a member function
int year;private:
int month;int day;
};#endif
#include “Date.h”
void main (){
CDate myBD(3, 31, 1996), yourBD;cout << "Enter your birthday as month, day, year ”; int m, d;cin >> m >> d >> yourBD.year;yourBD.setMonth(m);yourBD.setDay(d);if (myBD == yourBD)
cout << “Let’s celebrate together.”; }
bool operator ==(const CDate& day1, const CDate& day2){
return (day1.month == day2.month) &&day1. day == day2. day) &&day1.year == day2.year);
}
Rules for Overloading Operators• At least one argument must be of the class type.• Overloaded operators can be friends or member
functions.• Can only overload existing operators• Can’t change the number of arguments from the
original operator (binary (+), unary (++))• Can’t change precedence rules• Can’t overload dot operator(.), scope resolution
operator (::).• Overloading the assignment operator is a special
case.
Overloading Unary Operators
• Has only 1 object in the parameter list:– Negate: -– Increment: ++– Decrement: --
Overloading >> and <<
• The compiler does not automatically know how to output or input user-defined classes.
• Need to specify how each attribute is to be entered.
• Want input to be user friendly.– Ex: cin >> yourBD; // as format mm-dd-yyyy
• Want output to be clear and in standard form.– Ex: cout << yourBD; // as format mm/dd/yyyy
Arrays and Classes
• An array can be of any type.• Composite types (struct or class) can be
stored in arrays.• Ex:
CDate studentBDs[25];int n=5;if (studentBDs[n] == myBD)if (studentBDs[n].year < 1998)if (studentBDs[n].getMonth() == 3)
Arrays as Class Member
• Any composite type can contain an array.• Ex
class CStudentInfo{
…char name;SDate bDay;float quiz[5];
};CStudentInfo students[25], myBestStudent;myBestStudent.quiz[0] = 10;students[2].quiz[0] = 8;
Class CComplex definition//Complex.h#ifndef _COMPLEX_#define _COMPLEX_
#include <iostream>using namespace std;class CComplex{public:
CComplex(void);CComplex(double, double);CComplex(const CComplex&);~CComplex();
// Unary operator to negate the values of a complex number:// -(r, i) = (-r, -i)friend CComplex operator - (const CComplex& c);
// operator to add 2 complex numbers: // (r1, i1) + (r2, i2) = (r1+r2, i1+i2)friend CComplex operator + (const CComplex& left, const CComplex& right);
// operator to subtract 2 complex numbers:// (r1, i1) - (r2, i2) = (r1-r2, i1-i2)friend CComplex operator - (const CComplex& left, const CComplex& right);
// operator to multiply 2 complex numbers:// (r1, i1)(r2, i2) = (r1r2-i1i2, i1r2+r1i2)friend CComplex operator * (const CComplex& left, const CComplex& right);
// operator to compare if 2 complex numbers are the samefriend bool operator == (const CComplex& left, const CComplex& right);
// extraction operator to get input for real, imaginaryfriend istream& operator >> (istream& ins, CComplex& c);
// insertion operator to display a complex number as (a + bi)// where a is real and b is imagfriend ostream& operator << (ostream& outs, const CComplex& c);
private:
double real;double imag;
};#endif
Class CComplex implementationCComplex::CComplex(void) : real(0), imag(0){}CComplex::CComplex(double r, double i) : real(r), imag(i){}CComplex::CComplex(const CComplex& c) real(c.real), imag(c.imag){}CComplex::~CComplex() {}
CComplex operator - (const CComplex& c){
CComplex temp;temp.real = -c.real;temp.imag = -c..imag;return temp;
}CComplex operator + (const CComplex& left, const CComplex& right){
CComplex temp;temp.real = left.real + right.real;temp.imag = left.imag + right.imag;return temp;
}CComplex operator - (const CComplex& left, const CComplex& right){
CComplex temp;temp.real = left.real - right.real;temp.imag = left.imag - right.imag;return temp;
}
CComplex operator * (const CComplex& left, const CComplex& right){
CComplex temp;temp.real = left.real*right.real - left.imag*right.imag;temp.imag = left.imag*right.real + left.real*right.imag;return temp;
}bool operator == (const CComplex& left, const CComplex& right){
return (left.real == right.real) && (left.imag == right.imag);}
istream& operator >> (istream& ins, CComplex& c){
ins >> c.real >> c.imag;return ins;
}ostream& operator << (ostream& outs, const CComplex& c){
outs.setf(ios::fixed);outs.setf(ios::showpoint);outs.precision(2);
outs << '(' << c.real << ", ";if (c.imag > 0.0) outs << '+';outs << c.imag << “i)”;return outs;
}
Class CComplex implementation (used parameterized constructor)
CComplex::CComplex(void) : real(0), imag(0){}CComplex::CComplex(double r, double i) : real(r), imag(i){}CComplex::CComplex(const CComplex& c) real(c.real), imag(c.imag){}CComplex::~CComplex() {}
CComplex operator - (const CComplex& c){
return CComplex(-c.real, -c.imag);}
CComplex operator + (const CComplex& left, const CComplex& right){
return CComplex((left.real + right.real), (left.imag + right.imag));}
CComplex operator - (const CComplex& left, const CComplex& right){
return CComplex(left.real - right.real, left.imag - right.imag);}
CComplex operator * (const CComplex& left, const CComplex& right){
return CComplex((left.real*right.real - left.imag*right.imag), (left.imag*right.real + left.real*right.imag));
}
bool operator == (const CComplex& left, const CComplex& right){
return (left.real == right.real) && (left.imag == right.imag);}
istream& operator >> (istream& ins, CComplex& c){
ins >> c.real >> c.imag;return ins;
}
ostream& operator << (ostream& outs, const CComplex& c){
outs.setf(ios::fixed);outs.setf(ios::showpoint);outs.precision(2);
outs << '(' << c.real << ", ";if (c.imag > 0.0) outs << '+';outs << c.imag << “i)”;return outs;
}
Class with pointer data members#include "Date.h"CDate::Date () : month(1), day(1), year(new int(1900)){}CDate::Date (int m, int d, int y) : month(1), day(1), year(new int(y)){}CDate::~Date () {}
int CDate::getMonth(){
return month;}int CDate::getMonth(){
return month;}int CDate::getDay(){ return day;}void CDate::setMonth(int m){ month = m;}….
class CDate{public:
CDate(); // default constructorCDate(int m, int d, int y); // parameterized constructor~CDate(); // destructor
int getMonth(); // accessorint getDay(); // accessorvoid setMonth(int m); // mutatorvoid setDay(int d); // mutator
void display(); // a member function
int *year;private:
int month;int day;
};
Destructor
• Every class needs to tell the compiler how to destroy the object and return the memory to the freestore.
• Destructor is used to destroy a class object and return the memory to the heap. – In the case of standard variables, it will automatically return the
memory to the heap and the destructor is empty.– In the case of dynamic variables, it will destroy the pointer but not
return the memory to the heap unless we use the delete command.• With dynamic variables, only the pointer would be deleted and not what
it points to.• Need to write the destructor specifically and use delete.
• Automatically called when scope ends
Destructor (example)class CDate{public:
CDate(); // default constructorCDate(int m, int d, int y); // parameterized constructor~CDate(); // destructor
int getMonth(); // accessorint getDay(); // accessorvoid setMonth(int m); // mutatorvoid setDay(int d); // mutator
void display(); // a member function
int *year;private:
int month;int day;
};
#include "Date.h"CDate::Date () : month(1), day(1), year(new int(1900)){}CDate::Date (int m, int d, int y) : month(1), day(1), year(new int(y)){}CDate::~Date () {
cout <<“Bye-bye: ”<<month<<“-”<<day<<“-”<<*year<<endl;}…
#include "Date.h“void main () {
CDate myBD (1, 1, 1990);CDate yourBD (12, 31, 2000);
}
Bye-bye: 12-31-2000Bye-bye: 1-1-1990
Output:
So, what happens to the memory location reserved for year? Still occupied
Destructor (example)class CDate{public:
CDate(); // default constructorCDate(int m, int d, int y); // parameterized constructor~CDate(); // destructor
int getMonth(); // accessorint getDay(); // accessorvoid setMonth(int m); // mutatorvoid setDay(int d); // mutator
void display(); // a member function
int *year;private:
int month;int day;
};
#include "Date.h"CDate::Date () : month(1), day(1), year(new int(1900)){}CDate::Date (int m, int d, int y) : month(1), day(1), year(new int(y)){}CDate::~Date () {
cout <<“Bye-bye: ”<<month<<“-”<<day<<“-”<<*year<<endl;delete year;
}…
#include "Date.h“void main () {
CDate myBD (1, 1, 1990);CDate yourBD (12, 31, 2000);
}
Bye-bye: 12-31-2000Bye-bye: 1-1-1990
Output:
So, what happens to the memory address reserved for year? Freed
Copy Constructor• Creates a copy of an object in a different memory location. • Parameter list has one variable that is an object of the class.• The parameter is preceded by const and is a call by reference.
– Ex: CDate (const CDate& d);
• Called automatically whenever a function has a parameter of the class type.– Ex: CDate myBD(yourBD);
• Any classes using pointers and new operator (dynamic variables) should have a copy constructor. Otherwise, the compiler will only copy the pointers so they both have the same address (both point to the same memory address, rather than each point to the same data but in different addresses. This is called a “shallow copy”).
Copy Constructor (example)#include "Date.h“
CDate::CDate () : month(1), day(1), year(new int(1900)){}CDate::CDate (int m, int d, int y) : month(1), day(1), year(new int(y)){}CDate::~CDate () {
delete year;}
CDate::CDate (const CDate& d) : month(d.month), day(d.day), year(d.year){}
CDate::~CDate () {delete year;
} …
class CDate{public: CDate(); // default constructor CDate(int m, int d, int y); // parameterized constructor CDate(const CDate&); // copy constructor ~CDate(); // destructor
int getMonth(); // accessor int getDay(); // accessor void setMonth(int m); // mutator void setDay(int d); // mutator
void display(); // a member function
int *year;private: int month; int day;};
Copy Constructor (const.)#include "Date.h“void main () {
CDate myBD (1, 1, 1990);{ CDate yourBD (myBD); }cout << “My birth year is: ” << myBD.year << endl;
}
What happens to the memory address reserved for myBD’s year?
Destroyed by yourBD’s destructor
Output: ??? -17891602 (garbage)
Why garbage???
myBD’syear
yourBD’syear
1900
myBD’syear
yourBD’syear
?
Both myBD’s year and yourBD’s year point to the same memory address.When one is destroyed, the other becomes dangling pointer.
10,000
Copy Constructor (example)class CDate{public:
CDate(); // default constructorCDate(int m, int d, int y); // parameterized constructorCDate(const CDate&); // copy constructor~CDate(); // destructor
int getMonth(); // accessorint getDay(); // accessorvoid setMonth(int m); // mutatorvoid setDay(int d); // mutator
void display(); // a member function
int *year;private:
int month;int day;
};
#include "Date.h"CDate::CDate () : month(1), day(1), year(new int(1900)){}CDate::CDate (int m, int d, int y) : month(1), day(1), year(new int(y)){}CDate::~CDate () {
delete year;}CDate::CDate (const CDate& d) : month(d.month), day(d.day){
year = new int;*year = *(d.year);
}CDate::~CDate () {
delete year;} …
Copy Constructor (const.)#include "Date.h“void main () {
CDate myBD (1, 1, 1990);{ CDate yourBD (myBD); }cout << “My birth year is: ” << myBD.year << endl;
}
What happens to the memory address reserved for myBD’s year?
Still there and used by myBD’s year
Output: ??? 1990
Why exception NOT raised???
myBD’syear
yourBD’syear
1900
myBD’syear
yourBD’syear
?
Both myBD’s year points to a different memory address, not related to the address of yourBD’s year.
10,000 190011,000
190010,000
Overloading the Assignment Operator
• If NOT overloaded, the compiler will create one and that assignment operator will copy all the values of data members of the assigner (on the right) to the corresponding ones of the assignee (on the left).
• The “shallow copy” will happen if a data member is a pointer. So, the assignment operator needs to be overloaded to assign the pointer to another memory address.
void CDate::operator = (const CDate& d)
{
month = d.month;
day = d.day;
year = d.year;
}
Assignment Operator not overloaded
#include "Date.h“void main () {
CDate myBD (1, 1, 1990);{CDate yourBD = myBD; }cout << “My birth year is: ” << myBD.year << endl;
}
What happens to the memory address reserved for myBD’s year?
Destroyed by yourBD’s destructor
Output: ??? -17891602 (garbage)
Why garbage???
Both myBD’s year and yourBD’s year point to the same memory address.When one is destroyed, the other becomes dangling pointer.
myBD’syear
yourBD’syear
1900
myBD’syear
yourBD’syear
?
10,000
Overloaded Assignment Operator (example)
class CDate{public:
CDate(); // default constructorCDate(int m, int d, int y); // parameterized constructorCDate(const CDate&); // copy constructors~CDate(); // destructor
int getMonth(); // accessorint getDay(); // accessorvoid setMonth(int m); // mutatorvoid setDay(int d); // mutator
void display(); // a member functionvoid operator = (const CDate& d); // Assignment op.int *year;
private:int month;int day;
};
#include "Date.h"CDate::CDate () : month(1), day(1), year(new int(1900)){}CDate::CDate (int m, int d, int y) : month(1), day(1), year(new int(y)){}CDate::~CDate () {
delete year;}CDate::CDate (const CDate& d) : month(d.month), day(d.day){
year = new int;*year = *(d.year);
}CDate::~CDate () {
delete year;} void CDate::operator = (const CDate& d){
month = d.month;day = d.day;year = new int;*year = *(d.year);
}…
Overloaded Assignment Operator (const.)
#include "Date.h“void main () {
CDate myBD (1, 1, 1990);{ CDate yourBD (myBD); }cout << “My birth year is: ” << myBD.year << endl;
}
What happens to the memory address reserved for myBD’s year?
Still there and used by myBD’s year
Output: ??? 1990
Why exception NOT raised???
myBD’syear
yourBD’syear
1900
myBD’syear
yourBD’syear
?
Both myBD’s year points to a different memory address, not related to the address of yourBD’s year.
10,000 190011,000
190010,000
The Big Three
• Copy constructor, assignment operator and destructor are the big three of a class.
• Rule that if you need to define one of them, you need to define all of them or the compiler will create them but they might not work correctly!