Writing an Operator That Isnt a Member Function

Writing an Operator That Isn t a Member Function

Problem

You have to write a binary operator, and you can't or don't want to make it a class member function.

Solution

Use the operator keyword, a temporary variable, and a copy constructor to do most of the work, and return the temporary object. Example 15-5 presents a simple string concatenation operator for a custom String class.

Example 15-5. Concatenation with a nonmember operator

#include 
#include 

class String { // Assume the String class declaration
 // has at least everything shown here
public:
 String( );
 String(const char* p);
 String(const String& orig);
 ~String( ) {delete buf_;}

 String& append(const String& s);
 size_t length( ) const;
 const char* data( ) const;
 String& operator=(const String& orig);

 // ...
};

String operator+(const String& lhs, const String& rhs) {

 String tmp(lhs); // Copy construct a temp object
 tmp.append(rhs); // Use a member function to do the real work

 return(tmp); // Return the temporary
}

int main( ) {

 String s1("banana ");
 String s2("rancher");
 String s3, s4, s5, s6;

 s3 = s1 + s2; // Works fine, no surprises
 s4 = s1 + "rama"; // Constructs "rama" automatically using
 // the constructor String(const char*)
 s5 = "ham " + s2; // Hey cool, it even does it backward
 s6 = s1 + "rama " + s2;

 std::cout << "s3 = " << s3.data( ) << '
';
 std::cout << "s4 = " << s4.data( ) << '
';
 std::cout << "s5 = " << s5.data( ) << '
';
 std::cout << "s6 = " << s6.data( ) << '
';
}

 

Discussion

A standalone operator is declared and defined similarly to a member function operator. In Example 15-5, I could have implemented operator+ as a member function by declaring it like this:

String operator+(const String& rhs);

In most cases, this will work the same way regardless of whether you define operator+ as a member or nonmember function, but there are at least a couple of reasons why you would want to implement it as a nonmember function. The first is conceptual: does it make sense to have an operator that returns a new, distinct object? operator+ as a member function is not an inspector of the object's state, nor does it alter the object's state. It's a general utility function that happens to operate on Strings, and, therefore, should not be a member function.

The second reason is technical. You can't do the following with a member operator (from the example):

s5 = "ham " + s2;

This won't work because a character string doesn't have an operator+ that takes a String parameter. If, on the other hand, you have defined your standalone operator+ that takes two String parameters, your compiler will look to see if the String class has a constructor that takes a const char* argument (or whatever type you are using with a String) and construct a temporary object at runtime. The above code, therefore, is equivalent to this:

s5 = String("ham ") + s2;

The compiler saves you the extra keystrokes by just looking it up and invoking the constructor for you.

Overloading the left- and right-shift operators (<< and >>) for streams also requires that you use nonmember operators. For example, to put your new object to a stream using left-shift, you would have to declare operator<<, like this:

ostream& operator<<(ostream& str, const MyClass& obj);

Of course, you can subclass one of the standard library stream classes, and add all the left-shift operators you want, but is that really a good idea? If you do that, only code that uses your new stream class will be able to write your custom class's objects to it. If you use a standalone operator, any code in the same namespace can just write your object to an ostream (or read it from an istream) with no problem.





C++ Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2006
Pages: 241
Simiral book on Amazon

Flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net