230 likes | 982 Vues
Operator Overloading Fundamentals Methods (class members & friend functions) Binary operators Stream operators Unary operators Pre & post increment & decrement Fundamentals Operator overloading = using the same operator for different data types
E N D
Operator Overloading • Fundamentals • Methods (class members & friend functions) • Binary operators • Stream operators • Unary operators • Pre & post increment & decrement
Fundamentals • Operator overloading = using the same operator for different data types • For example, “+” is used to add int, float, double, etc. • Function definition is written the same as any other function • Except function name becomes “operator” followed by the symbol that you are overloading • operator+
Built-in Operators • A few operators don’t have to be explicitly overloaded (done automatically) • Assignment operator (=) • Memberwise assignment of class data members • Address operator (&) • Returns the address of the object in memory • Both can be explicitly overloaded
Restrictions • For a list of operators that can be overloaded • See D & D, p. 670 • Five operators cannot be overloaded • ., .*, ::, ?:, sizeof • These properties cannot be changed • Precedence: * has higher precedence than + • Associativity: (a + b) + c = a + (b + c) • Arity: number of operands that the operator takes (unary & binary operators)
Restrictions • Only existing operators can be overloaded • Overloading an assignment operator and an addition operator will not automatically overload the += operator F1 = F2 + F3; F1 += F2; • Misuse • Overloading the “+” operator to subtract
Method #1 • Class Members: overloading an operator by adding another method (member function) to the class itself • Must use this method for overloading (), [], -> or any of the assignment operators • Can use this method when the leftmost operand is a class object • This works fine with f1 = f2 + 2; which converts “2” to a fraction (via a conversion constructor) and adds it to f2 • But will not work with f1 = 2 + f2; since “2” is not of class fraction
Method #1 void main(){ Fraction a(1,3); Fraction b(2,3); Fraction c; c = a + b; c.print(); } class Fraction { int num, den; public: Fraction(int n=0, int d=1) :num(n),den(d){} Fraction operator+ (const Fraction &f){ Fraction temp; temp.num=num*f.den+f.num*den; temp.den=den*f.den; return temp;} void print() const{ cout<<num<<'/'<<den<<endl;} }; Note: c=a+b is interpreted as (see method1.txt) c.operator=(a.operator+(b))
Method #2 • Friend Functions: overloading an operator as a friend function (non-member function) of the class • Can use this method when the leftmost or rightmost operand is a class object • This will fix our problem when we have a different class object on the left side of an operator • Must use this method when the leftmost operand is NOT a class object (for example, cout<<f)
Method #2 void main(){ Fraction a(1,3); Fraction b(2,3); Fraction c; c = a + b; c.print(); } class Fraction { int num, den; public: Fraction(int n=0, int d=1) :num(n),den(d){} friend Fraction operator+ (const Fraction &a, const Fraction &b){ Fraction temp; temp.num=a.num*b.den+b.num*a.den; temp.den=a.den*b.den; return temp;} void print() const{ cout<<num<<'/'<<den<<endl;} }; Note: c=a+b is interpreted as (See method2.txt) c.operator=(operator+(a, b))
Why Does This Program Run? void main(){ Fraction a, b; a = a + 1; b = 2.5 + b; a.print(); //1/1 b.print(); //2/1 } (See run.cpp) class Fraction { int num, den; public: Fraction(int n=0, int d=1) :num(n),den(d){} friend Fraction operator+ (const Fraction &a, const Fraction &b){ Fraction temp; temp.num=a.num*b.den+b.num*a.den; temp.den=a.den*b.den; return temp;} void print() const{ cout<<num<<'/'<<den<<endl;} };
Because… • C++ will try and convert types to perform operations requested • Asks: Can I convert an “int” to a Fraction? • Yes, we have a constructor that takes and integer and returns the equivalent Fraction • System invokes constructor to build Fraction from int • What about “Fraction = double + Fraction? • Affirmative. Can convert double to int (truncate) • Can then convert int to Fraction (constructor)
Conversion Constructor • A constructor that transforms objects of one type into objects of another type • Write a constructor that will convert a double into a fraction (exercise1.txt)
Overloading Stream Operators • cin object • An instance of the istream class • operator>> • So cin>>a>>b; becomes • operator>>(cin,a); operator>>(cin,b); • cout object • An instance of the ostream class • operator<< • So cout<<a<<b; becomes • operator<<(cout,a); operator<<(cout,b);
Stream Operators class Fraction{ . . . friend istream & operator>>(istream &in, Fraction &f){ char ch; in>>f.num>>ch>>f.den; return in;} friend ostream & operator<<(ostream &out, const Fraction & f){ out<<f.num<<'/'<<f.den; return out;} }; int main(){ Fraction a,b; cin>>a>>b; cout<<a<<" "<<b<<endl; return 0; } (See stream.txt)
Overloading Unary Operators • Can be overloaded as a class member or as a friend function • For example, the logical not operator (!) • Will change true to false or false to true • Returns either true (non-zero) or false (zero) • Use bool (boolean) data type
Overloading Unary Operators • As a class member bool operator!() const; bool Fraction::operator!()const{ if(num) return false; return true; } • As a friend function friend bool operator!(const Fraction &); bool operator!(const Fraction &f){ if(f.num) return false; return true; } (See unary.txt)
Overloading ++ & -- • Preincrement • Original code: ++f1; • Compiler will generate: f1.operator++(); • Function prototype: Fraction &operator++(); • Returns a reference to itself
Overloading ++ & -- • Postincrement • Original code: f1++; • Compiler will generate: f1.operator++(0); • This is a “dummy value” to distinguish it from preincrement • Function prototype: Fraction operator++(int); • Value return, not a reference return
Unary Operators class Fraction{ . . . Fraction &operator++(){//preincrement num+=den; return *this;} Fraction operator++(int){//postincrement Fraction temp = *this; num+=den; return temp;} }; void main(){ Fraction a,b,c; b = ++a; //b.operator=(a.operator++()) c = a++; //c.operator=(a.operator++(0)) cout<<a<<" "<<b<<" "<<c<<endl; } (see prepost.txt)
Use of const • Why use const at the beginning of a function? • When that function returns a reference, the user may have direct access to the object’s data members • See const.txt
Class Exercise • What is the output of the following program (exercise2.txt)?