|
them.
Non-member operators
In some of the previous examples, the
operators may be members or non-members, and it doesn’t seem to make much
difference. This usually raises the question, “Which should I
choose?” In general, if it doesn’t make any difference, they should
be members, to emphasize the association between the operator and its class.
When the left-hand operand is always an object of the current class, this works
fine.
However, sometimes you want the left-hand
operand to be an object of some other class. A common place you’ll see
this is when the operators << and >> are overloaded
for
iostreams.
Since iostreams is a fundamental C++ library, you’ll probably want to
overload these operators for most of your classes, so the process is worth
memorizing:
//: C12:IostreamOperatorOverloading.cpp
// Example of non-member overloaded operators
#include "../require.h"
#include <iostream>
#include <sstream> // "String streams"
#include <cstring>
using namespace std;
class IntArray {
enum { sz = 5 };
int i[sz];
public:
IntArray() { memset(i, 0, sz* sizeof(*i)); }
int& operator[](int x) {
require(x >= 0 && x < sz,
"IntArray::operator[] out of range");
return i[x];
}
friend ostream&
operator<<(ostream& os, const IntArray& ia);
friend istream&
operator>>(istream& is, IntArray& ia);
};
ostream&
operator<<(ostream& os, const IntArray& ia) {
for(int j = 0; j < ia.sz; j++) {
os << ia.i[j];
if(j != ia.sz -1)
os << ", ";
}
os << endl;
return os;
}
istream& operator>>(istream& is, IntArray& ia){
for(int j = 0; j < ia.sz; j++)
is >> ia.i[j];
return is;
}
int main() {
stringstream input("47 34 56 92 103");
IntArray I;
input >> I;
I[4] = -1; // Use overloaded operator[]
cout << I;
} ///:~
This class also contains an overloaded
operator
[ ], which returns a reference to a legitimate value in the array. Because a
reference is returned, the expression
I[4] = -1;
not only looks much more civilized than
if pointers were used, it also accomplishes the desired effect.
It’s important that the overloaded
shift operators pass and return by reference, so the actions will affect
the external objects. In the function definitions, expressions
like
os << ia.i[j];
cause the existing overloaded
operator functions to be called (that is, those defined in
<iostream>). In this case, the function called is ostream&
operator<<(ostream&, int) because ia.i[j] resolves to an
int.
Once all the actions are performed on the
istream or
ostream, it is returned so it can be used in a
more complicated expression.
In main( ), a new type of
iostream is used: the stringstream
(declared in
<sstream>). This is
a class that takes a string (which it can create from a char
array, as shown here) and turns it into an iostream. In the example
above, this means that the shift operators can be tested without opening a file
or typing data in on the command line.
The form shown in this example for the
inserter and extractor is standard. If you want to create these operators for
your own class, copy the function signatures and return types above and follow
the form of the
body.
|
|