Home arrow C++ arrow Page 2 - Operator Overloading in C++
C++

Operator Overloading in C++


Operating overloading allows you to pass different variable types to the same function and produce different results. In this article Ben gives us the low-down on operator overloading in C++.

Author Info:
By: Ben Watson
Rating: 3 stars3 stars3 stars3 stars3 stars / 370
December 08, 2002
TABLE OF CONTENTS:
  1. · Operator Overloading in C++
  2. · Definition
  3. · Overloading =
  4. · Overloading
  5. · Matrix Multiplication - Overloading * Again
  6. · Putting It All Together
  7. · Conclusion

print this article
SEARCH DEVARTICLES

Operator Overloading in C++ - Definition
(Page 2 of 7 )

This can be a weird subject for some, especially those with a strong Java background, or another language that doesn't support this feature. It can be confusing even for excellent programmers. But it is a strong feature of C++ that, if mastered, can yield some increased productivity in programming.

We all know that an operator can be used in mathematical expressions:

int z=x+y;
float g=3.14*g;


Now wouldn't it be nice to use operators on our own objects to do what we want? For example, a string class could use + to concatenate, or a Throttle class could use the ++ and -- operators to increase or decrease throttle position. The operators can be programmed to do whatever we want them to.

However, some words of caution. Operator overloading provides NO additional functionality to your code. It just compiles to normal function calls. It's even written out like normal function calls. It is mainly for aesthetics. There is, however, one extremely useful set of operators to overload that makes life much easier: the streaming operators, which I will cover at the end.

Second, you should NOT use operator overloading for unobvious relationships. Using + to concatenate two strings intuitively makes sense to most programmers, so it's easy to use it like that. But how would you define string1*string2? or string1^string2? It isn't very clear what that means. So use caution when considering adding operators to your objects.

Sample Object
For my sample object, I'm going to implement a matrix. This won't be a full-scale implementation of every imaginable matrix operation, but it should be enough to cover the basics of operator overloading, and maybe whet your appetite to complete the implementation for other operations (dot product, inverse, determinant, etc.).

In order to completely encapsulate a matrix within a class, we actually need two classes: Row and Matrix.

So let's start with Row:

template<class T>
class Row {
public:
Row(int cols=0):row(NULL) {SetRowSize(cols);}
~Row() {SetRowSize(0); }
Row(const Row &r):row(NULL) {
SetRowSize(r.numCols);
for (int i=0;i<numCols;i++)
row[i]=r.row[i];
}

void SetRowSize(int n) {
if(row) delete[] row;
if (n>0) {
row=new T[n];
memset(row,0,sizeof(T)*n/sizeof(char));
}
else row=NULL;
numCols=n;
}

int size() { return numCols;}
private:
int numCols;
T* row;
};


Let's look at this before continuing on. Notice that I'm making it a template class. This is so you can have a matrix of all the usual numerical types, as well as any type you want to define yourself. The only requirement for the type is that it must have the +, -, and * operators defined on it. We'll get into how to do that. If you don't understand templates, you can think of all of the T's as ints for now.

SetRowSize() deletes any old data, and allocates space for new data, unless we set the number of columns to 0, in which case it merely deletes the data. This lets us use this function for construction, destruction, and dynamic modification in one method. Nifty, eh? The call to memset() just zeroes out the array after figuring out how many bytes the row uses and dividing this by the size of character, because memset() works in terms of chars.

I also defined a copy constructor, which will come in handy quite a bit, as we'll see later on when we copy matrices.

Overloading []
OK, let's overload our first operator: []

Yes, that's one operator. The array-access operator. It makes perfect sense here, because we have a linear array of objects we would like to access. Let's add this definition to our Row class:

T& operator[](int column) {
assert(column<numCols);
return row[column];
}


The arguments to our brackets are going to be integers specifying the index of the item we want, so that will be the function's arguments. Notice the syntax: [ReturnType] operator[Op]([argument list]). We do an assertion to make sure we're accessing memory within the array's bounds. If all is OK, we return a reference to the object. Why a reference instead of a value? It won't make much of a difference in a case like this:

Row<int> r(1);//1x1 matrix

int a=r[0];


a will get the value of r[0] whether a reference or a value is returned. However, if we return a reference, we can then change the value in the row from outside the class, using the [] accessor operator, like so:

Row<float> r(1);

r[0]=3.142;
float pi=r[0];


Very cool, isn't it.
blog comments powered by Disqus
C++ ARTICLES

- Intel Threading Building Blocks
- Threading Building Blocks with C++
- Video Memory Programming in Text Mode
- More Tricks to Gain Speed in Programming Con...
- Easy and Efficient Programming for Contests
- Preparing For Programming Contests
- Programming Contests: Why Bother?
- Polymorphism in C++
- Overview of Virtual Functions
- Inheritance in C++
- Extending the Basic Streams in C++
- Using Stringstreams in C++
- Custom Stream Manipulation in C++
- General Stream Manipulation in C++
- Serialize Your Class into Streams in C++

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials