Please see SVN Access for information regarding DokuWiki projects.
Your Donations help keep my Software going!

Operator Overloading for Manufactured Types

By Terence J. Grant 07/15/2006

Note The results of this article so far have only been tested with Microsoft Visual Studio 2005 and may not represent the generic case (gcc.)

Operator overloading in C++ is a very useful feature. It can be used, for instance, to extend the set of primitive types available in C++ –that is, to create new, albeit man-made, “primitive” types.

Recently, I've come to rely on C++ operator overloading for this very reason. However, I have been less than successful in finding a complete list of operators to overload to accomplish this. Thus I have compiled this list.

So, without further ado, here is a brief list of C++ operators you can overload for creating manufactured types, and the method of which to do so.

Generally Speaking...

In general, the form of operator overloading is the following:

some-type-a class-name::operatorX(some-type-b other);
some-type-a class-name::operatorX(some-type-b &other);

Where X represents a placeholder for a valid operator. The const keyword will also make appearances when necessary and is typically optional. When you see {const}, const with curly braces, this is an indication that it is purely optional and not required.

The classes/types some-type-a and some-type-b can be any classes or types, even the same class as class-name. And of course you can define as many operators for as many different class types as you like.

You'll notice that there are two options– by value and by reference. It appears that for all intents and purposes, you could use either. Most of the time however, it is best to play it safe and simply use references.

Also, I find most of the time I'll want to prefix each operator with inline, because again, we're talking generally about manufacturing new primitive types, and its good to hint to the compiler that we want to favor speed.

Construction and Assignment

Let's first mention that constructors are important. Constructors are not operators per se– they do go hand in hand with cast operators though, so it is important to mention the list of constructors to consider.

class-name::class-name();
{explicit} class-name::class-name(const class-type &other);
{explicit} class-name::class-name(const some-type-a &other);
{explicit} class-name::class-name(const some-type-b other);
{explicit} class-name::class-name(const some-type-c other);

For the parameterless constructor, typically you'll just leave it as an empty method, to mimic what happens when you don't initialize a primtive type.

For constructors with parameters, you'll want to typically use const so that you're not tempted to modify the initializer.

You may also wish to use the explicit keyword if you don't want an auto-conversion from some type to your class type. You may still explicitly construct your class with the other type.

Standard assignment is similar.

class-type& class-name::operator=(const some-type-b &other);

If you do not define the assignment operator, the constructor will be used to create a temporary object, and then the copy constructor will be used. (This is potentially a longer set of operations.)

Cast

During casting you will typically want to support the same types that you initialize with.

operator some-type-b();

Neither the const keyword nor the explicit keyword is supported in this case.

Unary Minus

This is the arithmetic negation operation.

{const} some-type-a class-name::operator-() const;

Arithmetic Binary Operators

Here are the standard arithmetic binary operators.

{const} some-type-a class-name::operator+(const some-type-b &other) const;
{const} some-type-a class-name::operator-(const some-type-b &other) const;
{const} some-type-a class-name::operator*(const some-type-b &other) const;
{const} some-type-a class-name::operator/(const some-type-b &other) const;
{const} some-type-a class-name::operator%(const some-type-b &other) const;

Arithmetic Assignment

Notice that you return a reference. The reference you are to return is this.

class-type& class-name::operator+=(const some-type-b &other);
class-type& class-name::operator-=(const some-type-b &other);
class-type& class-name::operator*=(const some-type-b &other);
class-type& class-name::operator/=(const some-type-b &other);
class-type& class-name::operator%=(const some-type-b &other);

Unary Binary Negation

This is the binary negation operation.

{const} some-type-a class-name::operator~() const;

Bitwise Binary Operators

Here are the standard arithmetic binary operators.

{const} some-type-a class-name::operator&(const some-type-b &other) const;
{const} some-type-a class-name::operator|(const some-type-b &other) const;
{const} some-type-a class-name::operator^(const some-type-b &other) const;
{const} some-type-a class-name::operator<<(const some-type-b &other) const;
{const} some-type-a class-name::operator>>(const some-type-b &other) const;

Bitwise Assignment

Notice that you return a reference. The reference you are to return is this.

class-type& class-name::operator&=(const some-type-b &other);
class-type& class-name::operator|=(const some-type-b &other);
class-type& class-name::operator^=(const some-type-b &other);
class-type& class-name::operator<<=(const some-type-b &other);
class-type& class-name::operator>>=(const some-type-b &other);

Increment and Decrement

Notice that you return a reference. The reference you are to return is this.

class-type& class-name::operator++();    //prefix:  ++this
class-type& class-name::operator--();    //prefix:  --this
const class-type class-name::operator++(int);  //postfix: this++
const class-type class-name::operator--(int);  //postfix: this--

For postfix operators, save a temporary copy of this, perform the increment/decrement on this, but return the older version.

Comparison Operators

Here is a list of all relational and logical comparisons.

const bool class-name::operator==(const some-type-a &other);
const bool class-name::operator!=(const some-type-a &other);
const bool class-name::operator<=(const some-type-a &other);
const bool class-name::operator>=(const some-type-a &other);
const bool class-name::operator<(const some-type-a &other);
const bool class-name::operator>(const some-type-a &other);

Friend Binary Operators

Typically you'll want to keep your internal representation of a type protected, but you'll want to do operations like int + type as well as type + int. Though int + type is not supported above. So in these kind of cases, you'll need to invoke a “friend”-based operator function.

Operator functions exist outside of classes, and can be used to define operations on two different(or similar) types at any time.

So for example, let's say you want to overload operator+ for both int + mytype, and mytype + int. You'll need to do the following:

First, place this within your class declaration:

friend const some-type-a operator+(const mytype &a, const int &b);
friend const some-type-a operator+(const int &b, const mytype &a);

Then outside of the class, define the functions as needed:

const some-type-a operator+(const mytype &a, const int &b);
const some-type-a operator+(const int &b, const mytype &a);

And that pretty much covers all the operations you'll want to use on manufactured types.


Personal Tools