190 likes | 404 Views
Operators. An operator is (just) a convenient way to write a function call. There is a fixed set of symbols that can be used as operators, like: + - * ! += < ... C++ allows the definition of operators for classes.
E N D
Operators An operator is (just) a convenient way to write a function call. There is a fixed set of symbols that can be used as operators, like: + - * ! += < ... C++ allows the definition of operators for classes. But priorities (operator precedence) can not be changed: the bracketing of an expression never changes. A = B + C; A = sum( A, C ); add( A, B, C ); A * B + C & D == (( A * B ) + C ) & D
Unary and Binary operators Unairy (monadic) operators (one argument): ++ -- & + - * Binary (diadic) operators (two arguments): = == += >= << + - & a++; b—; f( &c ); x = +d; y = -d; *p = *q; a = b; if( a == b ){ . . . } c += 5; while( a >= b ){ . . . } a = a << 2; a = a + b; a = a – b; a = a & 0x0F;
Defining an operator Operator @ (if it existed) would be defined by the function operator@ (operator is a reserved word). int operator@( Clock c ){ return 42; } A monadic operator has one argument. const Clock operator+( Clock c ){ return c; } A diadic operator has two arguments. const Clock operator+( const & Clock c, const & Clock d ){ int s = c.readSec() + d.readSec(); int m = c.readMin() + d.readMin() + ( s / 60 ); int h = c.readHour() + d.readHour() + ( m / 60 ); return Clock( h % 24, m % 60, s % 60 ); }
Defining a class operator Like other class functions, the first argument is implicit. But we still need a place to specify the lhs as const. class Clock { . . . Clock operator+( const & Clock d ) const; } A class operator has direct access to the attributes of the class, even inside the d parameter. But you don’t need to use direct access. (Why might it be wise not to?) Clock Clock::operator+( const & Clock d ) const { int ss = s + d.s; int mm = m + d.m + ( ss / 60 ); int hh = readHour() + d.readHour() + ( mm / 60 ); return Clock( hh % 24, mm % 60, ss % 60 ); }
Using a class operator Operators can be called directly or indirectly. class Clock { const Clock operator+( const & Clock d ) const; } Clock c, d, e; c = d.operator+( e ); c = d + e; A class operator has direct access to the attributes of the class, even to the d parameter. But you don’t need to use direct access. (Why could it be wise not to?) Clock Clock::operator+( const & Clock d ) const { int ss = s + d.s; int mm = m + d.m + ( ss / 60 ); int hh = readHour() + d.readHour() + ( mm / 60 ); return Clock( hh % 24, mm % 60, ss % 60 ); }
A monadic class operator A monadic class operator has zero arguments (why?). class Clock { const Clock operator+( void ) const; } const Clock Clock::operator+( void ) const { return *this; } Sometimes you have to refer to ‘yourself’.
Don’t confuse the user Preserve the semantics of the existing operators. You can define operator+ to do multiplication... Class C . . . C a, b, c; // addition + assignment a = b + c; // assignment + assignment-addition a = b; a += c; There is no operator=. How do you define assignment?
Cascaded assignments Preserve the possibility and meaning of cascaded assignments and assignment-operators. Class C . . . C a, b, c; a = b = c; // this means: a = ( b = c ); // should be same as: // b = c; // a = b; a += b + = c; // this means: a += ( b += c ); // should be same as: // b += c; // a += b;
The return type of assignments What do the red words mean? So which ones do we want? const my_int & operator=( const my_int & rhs ) const; a = b; // should this be allowed to change b? ( a = b ) = c; // this should be possible
The return type of assignments I can’t change my lhs??? I won’t change my rhs. X const my_int & operator=( const my_int & rhs ) const; // prevent this: ( a = b ) = c; So no need to make a copy of it. No need to make a new object.
A vector class • Vector : like an array, but: • Size set when created (not at compilation). • Lower bound is set at creation. • Index range can be queried. • Acces is checked against the index range. • Vector operations: == != + += =
A vector class – interface 1 class Vector { public: // Constructors. Vector ( int first_index = 1, int n = 0 ); Vector ( const Vector & v ); // Destructor ~Vector () { delete [] pVec; } // Public operations. int first ( void ) const { return i1; } int last ( void ) const { return i1 + num - 1; } int length ( void ) const { return num; } int read ( int index ) const; void change ( int index, int value ); . . . private: // The internal representation of a vector. const int i1; // first index int * pVec; // pointer to array of integers int num; // number of elements };
A vector class – interface 2 class Vector { public: . . . // Comparison operators bool operator==( const Vector & rhs ) const; bool operator!=( const Vector & rhs ) const { return !(*this == rhs); } // Assignment operators const Vector & operator= ( const Vector & rhs ); const Vector & operator+=( const Vector & rhs ); const Vector & operator+=( int n ); // Binary operators Vector operator+( const Vector & rhs ) const; Vector operator+( int n ) const; // Unary operators const Vector & operator+( void ); . . . }; What exactly does this mean? Lots of other operators could be defined, like: - ++ -- * / %
A vector class – creators, access Vector::Vector( int first_index, int n ): i1( first_index ), num( n ) { assert( num >= 0 ); pVec = new int[ num ]; } Vector::Vector( const Vector & v ): i1( v.i1 ), num( v.num ) { pVec = new int [num]; for (int i = 0; i < num; i++){ pVec[i] = v.pVec[i]; } } int Vector::read (int index) const { assert (index >= i1 && index <= last ()); return pVec[index - i1]; } void Vector::change (int index, int val){ assert (index >= i1 && index <= last ()); pVec[index - i1] = val; } If possible, use initializers. Check and allocate. Allocate and copy. Why no check? Range checks.
A vector class – equality, assignment bool Vector::operator== (const Vector & rhs) const { if (num != rhs.num){ return false; } for (int i = 0; i < num; i++){ if (pVec[i] != rhs.pVec[i]){ return false; } } return true; } const Vector & Vector::operator= (const Vector & rhs){ if (this != &rhs){ delete [] pVec; num = rhs.num; pVec = new int [num]; for (int i = 0; i < num; i++){ pVec[i] = rhs.pVec[i]; } } return *this; } Different sizes can’t be equal. Why this check? Note something mising here? Result is lhs, or copy of lhs?
A vector class – addition Can’t add different sizes. const Vector & Vector::operator+= (const Vector & rhs){ assert (num == rhs.num); for (int i = 0; i < num; i++){ pVec[i] += rhs.pVec[i]; } return *this; } const Vector & Vector::operator+= (int n){ for (int i = 0; i < num; i++){ pVec[i] += n; } return *this; } Vector Vector::operator+ (const Vector & rhs) const { Vector sum (*this); sum += rhs; return sum; } Why do we need a copy? What exactly happens here?
Addition the wrong way Vector & Vector::operator+ (const Vector & rhs) const { Vector sum (*this); sum += rhs; return sum; } • One character added. • What difference does this one character make? • Why is this version wrong?
A vector class – addition Vector Vector::operator+ (int n) const { Vector sum (*this); sum += n; return sum; } const Vector & Vector::operator+ (void){ return *this; }