1 / 30

C++ Certificate Program C++ Intermediate

C++ Certificate Program C++ Intermediate. Operator Overloading. Why?. Operator overloading provides no new capabilities in C++ Semantic sugar Provides conventional (and more convenient) notation for manipulating class objects

Télécharger la présentation

C++ Certificate Program C++ Intermediate

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. C++ Certificate ProgramC++ Intermediate Operator Overloading

  2. Why? • Operator overloading provides no new capabilities in C++ • Semantic sugar • Provides conventional (and more convenient) notation for manipulating class objects • Often better presents class semantics (particularly for value classes)

  3. Generic Programming and Operators • However, operator overloading can be crucial in template functions and classes: template <typename T> T sum (T x) { return (x < 1 ? 0 : x + sum(x-1)); } • The above function treats class and built-in types equivalently (with the same syntax)

  4. Traditional String Manipulation char const * str1 (“abc”); char const * str2 (“def”); char const * str3 (“ghi”); char full_string[64]; strcpy(full_string, str1); strcat(full_string, str2); strcat(full_string, str3); fprintf(“string is now ‘%s’.\n”, full_string); // outputs “string is now ‘abcdefghi’.”

  5. Operators Overloaded std::string const str1 (“abc”); std::string const str2 (“def”); std::string const str3 (“ghi”); std::string full_string (str1); // copy ctor full_string += str2; // operator += overloaded full_string += str3); cout << “string is now ‘“ << full_string << ‘’.\n”; // outputs “string is now ‘abcdefghi’.”

  6. ->, = Operators • ‘pointer to’ operator T *tp = new class T; tp->myMethod(); // same as (*tp).myMethod(); • Equality operator a == b; // overload needed for class types

  7. Limitations • Anything you can do with operators can be done via methods (reverse is not true) • Some operators may not be overloaded • Can only overload existing operators – new operators may not be defined • Limited to syntax defined in the C++ grammar (explained in more detail later)

  8. What Can be Overloaded • ‘Normal’ Operators + - * / % & ^ | >  < ! = ~+= -= *= /= %= &= ^= |= >= <= != == ~= && || ++ -- >>= <<= • ‘Special’ operators [] () -> ->* , << >>   new, delete, new[], delete[]

  9. What Cannot be Overloaded :: . .* • Scope resolution operator, as in namespace::identifier • Member selection, as in T.member • Member selection through pointer to member, as in T.*member • These all take a name rather than a value as the second operand

  10. Declaration • returntype ‘operator’ symbol (parameters) • Perhaps most common is the assignment operator T& operator= (T const &);

  11. Binary Operators • Non-static member function taking one argument class X { public: X & operator = (X const &); } • The LHS is the object itself

  12. Binary Operators • Non-member function taking two arguments void operator + ( X a, X b ); • This function has no special access to internals of class X • For operator @,aa@bb can be interpreted as aa.operator@ (bb) or operator@(aa,bb)

  13. Unary Operators • Non-static member function taking no arguments class X { public: X & operator ++(); // prefix ++ }; • Again, the LHS is the object itself • For operator @, @aa can be interpreted as aa.operator@ () or operator@(aa)

  14. Unary Operators • Non-member function taking one argument void operator* (X& x); // deref op • As with binary operators, this function has no special access to internals of class X

  15. Member vs Non-Member Recommendations • Method (member function): All unary operators • Must be a method: = () [] -> • Method: += -= /= *= ^= &= |= %= >>= <<= • All other binary operators: Non-member (global) function

  16. “Special” operators • May be thought of as having no strongly predefined meaning • For example: “Array” subscript operator, functor aids, memory allocation, conversion operators

  17. Operator Details • Most binary and unary operators can be either methods or global functions • Method versions are applied to LHS of the expression (binary ops) or directly to object (unary ops) • Example expression: x = y + 2; either a global or a member version works

  18. Grammatical Coherence • Operator “arity” cannot be changed class X { X operator/(); // err, not unary op X operator &(X,X); // err, not ternary }; X operator % (X); // err, not unary

  19. Predefined Meanings • Only a few assumptions are made operator= operator[] operator() operator-> • Must be non-static member functions, are assured an L-value is possible

  20. Redundant Operators and Pre-Defined Meanings • Built-in type operator equivalences not carried over – for int: a++ means a+=1, means a=a+1 • For class operator overloading, no equivalences: X operator++(int) // postfix version • does not automatically define X operator+= (int) • Associativity and precedence cannot be changed from built-in grammar rules

  21. Redundancy • Given x = x + 2, x = 2 + xis NOT necessarily valid (transitivity is not assumed) • Compiler cannot assume intent from operator semantics • For example, two operators are needed: T operator+ (int left, T const& right );T operator+ (T const& left, int right ); • First version (left op is integer) can’t be method (since would require adding method to built-in type int)

  22. Redundant Operators x = x + 1; x += 1; x++; ++x; • Gives 5 possible operations – all must be overloaded for class (user-defined) types (although copy assignment might be compiler generated)

  23. Operators and Class Types • An operator function must be either a member function or take at least one argument of class (user-defined) type • C++ not intended to be mutable - cannot change expression rules, but meanings in the context of a user-defined object can be defined • Thus, operators cannot be defined that operate exclusively on pointers • For member functions, the first operand must be a user-defined object

  24. Operators in Namespaces namespace std { class ostream { ostream &operator << (char const *); }; extern ostream cout; typedef basic_string<char> string; ostream & operator << (ostream &, string const &); } // end namespace std int main() { char const * p = “hello”; std::string s (“world”); std::cout << p << “, “ << s << endl; }

  25. Actual Function Calls std::cout << p becomes std::cout.operator <<(char const *) and std::cout << str becomes std::operator<<(std::cout, s)

  26. Name Lookup Rules • Name resolution follows same rules as regular functions, namespace std searched for appropriate operator overload: • x @ y is resolved: • If X is class type, look for operator @ as a member of X or base of X • Look for declarations of operator @ in the context surrounding x @ y, and • If X is defined in namespace N, look for declarations of operator @ in N • If Y is defined in namespace M, look for declarations of operator @ in M

  27. Constructors and Conversions int operator +(X,Y); int operator +(Y,X); int operator +(X,Z); int operator +(Z,X); int operator +(Y,Z); int operator +(Z,X);

  28. Constructors and Conversions • If conversions defined: X(Y); X(Z); • Would only then need to code: int operator +(X,X); The statement int val (x + y); would result in x + X(y) invoking int operator + (X,X);

  29. Prefer Prefix Increment vs Postfix • Using prefix ++ typically more efficient than postfix (never less efficient) • Postfix ++ requires a temporary value to be stored and returned by value • Built-in types may be optimized, class types typically not (in particular, iterator classes) • Good style – prefer prefix increment, only use postfix when necessary as part of expression

  30. Share Implementations When Appropriate class BigInt { // … BigInt& operator+= (int); BigInt& operator++ (); // prefix increment BigInt operator++ (int); // return by value }; BigInt& BigInt::operator+= (int) { // … return *this; } BigInt& operator++ () { return *this += 1; } BigInt operator++ (int) { BigInt tmp(*this); *this += 1; return tmp; }

More Related