Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Thinking in C++
Prev Contents / Index Next
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.

Thinking in C++
Prev Contents / Index Next

 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire