Contents |
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 :).
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);
}
#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.
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;
...
}
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
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.