1 / 24

Overloading

Overloading. Overloading allows a function or operator to have a different meaning depending on the type of objects it is used on. Examples: operator+ can be applied to both integers and strings. When applied to integers, it adds them. When applied to strings it concatenates them.

winship
Télécharger la présentation

Overloading

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Overloading • Overloading allows a function or operator to have a different meaning depending on the type of objects it is used on. • Examples: • operator+ can be applied to both integers and strings. When applied to integers, it adds them. When applied to strings it concatenates them. • We may wish to have more than one constructor for a class, depending on what inputs are specified by the user

  2. Overloading • A function with the same name as an existing one but a different number and/or types of parameters is an overloaded instance of the existing function. • If two functions have the same name and same number and types of parameters, they cannot have different return types. This would be an error.

  3. Overloading • Example 1: The maximum() function can be used to find the largest of three or the largest of two integers. int maximum (int x, int y) { return (x>y)? x : y; } int maximum (int x, int y, int z) { if (x < y) return (y < z)? z : y; else return (x < z)? z : x; } int main () { cout << maximum(3,4) << endl; cout << maximum(3,8,-1) << endl; return 0; } screen output: 4 8

  4. Overloading • Example 2: Consider a Fraction class. There are several places where we can use overloading: • An additional constructor that takes as arguments initial numerator and denominator values • A plus (+) operator to add two fractions. • The output stream operator (<<) to be able to use cout to print a Fraction.

  5. Overloading • Example 2: Overloading constructors int main () { Fraction f1; Fraction f2(3,4); f1.print(); cout << endl; f2.print(); return 0; } class Fraction { private: int numerator; int denominator; public: Fraction() { numerator = denominator = 1; } Fraction(int num, int den) { numerator = num; denominator = den; } void print() { cout << numerator << "\n--\n" << denominator << endl; } ... }; 1--1 3--4 screen output:

  6. Overloading • Example 2: Overloading constructors • We may also "merge" the two constructors into one by using default arguments. • Careful! The default arguments must be the last (rightmost ones) class Fraction { private: int numerator; int denominator; public: Fraction(int num=1, int den=1) { numerator = num; denominator = den; } void print() { cout << numerator << "\n--\n" << denominator << endl; } ... }; int main () { Fraction f1; Fraction f2(3,4); f1.print(); cout << endl; f2.print(); return 0; } 1--1 3--4 screen output:

  7. Overloading • Example 3: Overloading the + operator int main () { Fraction f1(1,4); Fraction f2(3,4); Fraction sum; sum = f1+f2; sum.print(); return 0; } class Fraction { private: int numerator; int denominator; public: Fraction(int num=1, int den=1) { numerator = num; denominator = den; } Fraction operator+ (const Fraction& addend) { Fraction result; result.numerator = numerator * addend.denominator \ + denominator * addend.numerator; result.denominator = denominator * addend.denominator; return result; } void print() { cout << numerator << "\n--\n" << denominator << endl; } ... }; 16--16 screen output:

  8. Overloading • Example 3: Dissecting the overloaded operator+ Fractionoperator+ (const Fraction& addend); sum = f1+f2; is equivalent to sum =f1.operator+(f2); Apply operator+ to the current object (f1). Pass the addend, f2, as an argument to the operator. Get back the sum and assign it to a variable.

  9. Overloading • Example 4: Overloading the << operator • We want to be able to type cout << f1;instead of f1.print(); • But this is different from the + operator: • cout << f1; is equivalent to operator<<(cout, f1) • This means that operator<< cannot be a member of the Fraction class (as it is not applied on a Fraction object). • The overloaded operator<< will be defined globally, outside the class. • Furthermore, it should return a reference to an ostream object in order to allow chained output (e.g. cout << f1 < f2;) • Why is this safe?

  10. Overloading • Example 4: Overloading the << operator class Fraction { ... }; ostream& operator<< ( ostream& out, Fraction frac) { out << frac.getNumerator() << "\n---\n" << frac.getDenominator() << endl; return out; } int main () { Fraction f1(3,4); cout << f1; return 0; } 3--4 screen output:

  11. operator= • Consider the following chunk of code: • The assignment is translated to f1.operator=(f2) • A copy of f2 is placed and is assigned to f1 • The compiler will perform a member by member assignment • This can cause problems when dynamic memory is involved. • We must overload the assignment operator, so that it performs a deep assignment. int main () { Fraction f1(3,4); Fraction f2; f2 = f1; return 0; }

  12. operator= • Example: class ClassInfo { private: int *student_ids; int class_size; public: ClassInfo (int size=0) { if (size == 0) student_ids = NULL; else student_ids = new int[size]; class_size = size; } void read_ids() { for (int i=0; i<class_size; i++) { cout << "Enter next id: "; cin >> student_ids[i]; } } }; int main () { ClassInfo eecs231(5); eecs231.read_ids(); ClassInfo eecs211(3); eecs211.read_ids(); eecs211 = eecs231; ...

  13. operator= and pointers 1:ClassInfo eecs231(16); eecs231.read_ids(); eecs231: 10 9 13 2 7 8 5 2: ClassInfo eecs211; eecs211: 1 16 3 3 3: eecs211 = eecs231; eecs231: 10 9 13 2 7 8 5 eecs211: 1 16 3 5

  14. operator= and pointers • Not only do both objects point to the same memory, even though they are difference objects, but we also have a memory leak because we lost the original eecs211.student_idspointer. • We must perform a deep assignment!

  15. operator= and pointers think of obj1 = obj2; as being equivalent to obj1.operator=(obj2); returning a reference to the current object allows chain assignments: obj1 = obj2 = obj3; pass the right-hand-side as a reference but do not allow it to be modified. ClassInfo& operator= (const ClassInfo& rhs) { if ( this == &rhs ) return *this; if ( student_ids != NULL) delete [ ] student_ids; student_ids = new int[rhs.class_size]; class_size = rhs.class_size; return *this; } the this pointer provides access to an object's own address. this is a C++ keyword.

  16. operator= and pointers ClassInfo& operator= (const ClassInfo& rhs) { if ( this == &rhs ) return *this; if ( student_ids != NULL) delete [ ] student_ids; student_ids = new int[rhs.class_size]; class_size = rhs.class_size; return *this; } if the right-hand side and the left-hand side are identical, (e.g. obj1 = obj1) just return a reference to the current object. (What will happen if we don't check this?)

  17. operator= and pointers ClassInfo& operator= (const ClassInfo& rhs) { if ( this == &rhs ) return *this; if ( student_ids != NULL) delete [ ] student_ids; student_ids = new int[rhs.class_size]; class_size = rhs.class_size; return *this; } Since the current object will be assigned a new value, make certain that any memory already allocated for it is properly deallocated.

  18. operator= and pointers ClassInfo& operator= (const ClassInfo& rhs) { if ( this == &rhs ) return *this; if ( student_ids != NULL) delete [ ] student_ids; student_ids = new int[rhs.class_size]; class_size = rhs.class_size; return *this; } Finally, perform the actual assignment and return a reference to the current object.

  19. pointer data members • Whenever a class has at least one data member that is a pointer, you MUST write • a destructor • a copy contructor • an overloaded assignment operator THE BIG THREE! If you need one of them, then you also need the other two!

  20. friend functions • In many cases, we would like a function to have access to private data members of the class, without the function being a member of the class. • Examples: • operator<< needs to print data member values but is not a class member itself. • a function that needs to operate on two or more objects of the same class • e.g. a function that takes as arguments two Points and computes the distance between them • a function that needs to operate on objects of different classes. • e.g. a function HaveCollided() that takes as arguments a Ship and a Torpedo object. • Possible Solution: • Use a get method (a.k.a. accessor) that returns the values of the class data members • Use friends!

  21. friend functions • A class may allow a function to access its private data members by declaring it as a friend function. • Example: class Torpedo; class Ship { private: ShipT type; char *name; Coords position; public: ... friend bool HaveCollided(Torpedo& , Ship& ); }; ... bool HaveCollided(Torpedo& t, Ship& s) { ... }

  22. friend classes • We may also declare a class A to be a friend of class B. This will give A access to the private members of B. • IMPORTANT: This does not mean that B has access to the private data members of A. In other words, if A is a friend of B, B is not automatically a friend of A. class City { private: Coords latitude; Coords longitude; public: ... friend class CityNetwork; }; class CityNetwork { private: City *citylist; Road *highways; public: ... }; Now, CityNetwork can access latitude and longitude

  23. evil friends? • Friendship may only be granted, not taken. • Keep in mind that a friend function is dependent on the implementation of the class that declared it as a friend. • If the implementation changes, the function may need to be modified and will certainly need to be recompiled. • You must always have very good reasons for using friends. • See also:http://www.parashift.com/c++-faq-lite/friends.html#faq-14.2

  24. operator<< as a friend classinfo.h class ClassInfo { private: int *student_ids; int class_size; public: ClassInfo (int size=0); .... friend ostream& operator<< (ostream&, const ClassInfo&) }; classinfo.cpp ClassInfo::ClassInfo (int size) { .... } ostream& operator<< (ostream&, const ClassInfo& obj) { ... }

More Related