C++ Operators

From Schmid.wiki
Jump to: navigation, search

Contents

Operators

The following pairs of operators are synonyms in standard C++ (works in gcc):

and     &&
or      ||
not     !
not_eq  !=
bitand  &
and_eq  &=
bitor   |
or_eq   |=
xor     ^
xor_eq  ^=
compl   ~ (one's complement)

I recommend using the spelled-out versions like or and not, as they are more readable than their symbolic counterparts. C++ is operator-heavy enough already :).

Operator Overloading

Members or Friends?

C++ translates the expression

<object> <operator> <value>           (e.g. vector * 4)

into

<object>.operator<operator>(<value>)  (e.g. vector.operator<*>(4))

If we want to overload an operator where the left operand isn't necessarily a class type, e.g.

4 * vector

we should use non-member overloaded operators, e.g.:

class Vector {
    friend Vector& operator*(double s);
    ...
    private:
        double x, y;
};
Vector& operator*(double s) {
    return Vector(x*s, y*s);
}

Overloading <<

Simple Example

#include <iostream>
using namespace std;

class Vector {
    friend ostream& operator<<(ostream&, const Vector&);
    ...
};
ostream& operator<<(ostream& out, const Vector& v) {
    out << "(" << v.x << "," << v.y << ")";
    return out;
}

vector

Here's an example on how to overload the << operator on the vector template class:

template<class T> ostream& operator<<(ostream &o, const vector<T> &v) {
    typename vector<T>::const_iterator i;
    for(i = v.begin(); i != v.end()-1; ++i) o << *i << ", ";
    return o << *i << "\n";                                                                       }       
}

Then you could simply print a vector like this:

vector<int> v(10);
for(int i = 0; i < 10; ++i) v[i] = i * i; // create vector of 10 squares
cout << v << endl;                        // print

ostream_iterator

Using ostream_iterator<> and copy to output from a Container:

#include <iostream>
#include <vector>
#include <iterator> // ostream_iterator<T>
using namespace std;

struct Animal {
    Animal(const char* s) : name(s) {}
    const char *name;
};

// Animal& *MUST* be const, see below for explanation
ostream& operator<<(ostream& os, Animal& a) { return os << a.name; }

int main(void) {

    vector<Animal> animals;
    animals.push_back(Animal("horse")); animals.push_back(Animal("goat"));

    // output animal names to cout
    // For every value of 'animals', deference ostream_iterator and assign the
    // animal. This assignment invokes cout << animal << ",":
    copy(animals.begin(), animals.end()-1, ostream_iterator<Animal>(cout, ","));
    cout << *(animals.end()-1) << endl;

    exit(EXIT_SUCCESS);
}

Output:

horse,goat

From /usr/lib/gcc/i686-pc-linux-gnu/4.1.1/include/g++-v4/bits/stream_iterator.h:

ostream_iterator& operator=(const _Tp& __value) {
  *_M_stream << __value;
  if (_M_string) *_M_stream << _M_string;
  return *this;
}

Note that __value MUST be const, and therefore the << operator MUST take a const Animal&, otherwise the << operator could change something in the Animal, and ostream_iterator would not be a model of Output Iterator.

Overloading Casting

class Theorem {
    public:
        Theorem(const string& t, int v) { text = t; value = v; }
        operator string() { return text; }
        operator bool()   { return value > 0; }
    ...
};
int main(void) {
    Theorem th("overloading is cool", 1);
    if(th) cout << (string) th << ": true." << endl;
    ...
}

Call Operator

Overload the call operator, if a class is a function object, i.e. has a single predominant operation.

Example:

class Exponentiation {
    int exp;
public:
    Exponentiation(int exp) : exp(exp) {}
    void operator()(int& x) {
        int e = exp, base = x;
        while(--e) { x *= base; }
    }
};
...
vector<int> v(10);
for(int i = 0; i < 10; i++) v[i] = i+1;          // 1..10
for_each(v.begin(), v.end(), Exponentiation(3)); // v[n]^3
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));

Outputs:

1 8 27 64 125 216 343 512 729 1000

Dereferencing Operator

The dereferencing operator has some fairly odd semantics.

struct Data { char *name; int value; };
class Smart_data_pointer {
    Data *ptr;
public:
    Smart_data_pointer(Data &ptr) : ptr(&ptr) {}
    Data *operator->() { return ptr; }
};
...
Data d = { "two", 2 };
Smart_data_pointer sp(d);
cout << sp->name << endl;

So we have that sp->name = (sp.operator->())->name.

Personal tools