Skip to main content
gamedev.net
🔒 Locked

Function Operator Overloading

Started by RSKueffner Jan 28, 2009 at 9:54 PM 21 replies 1.9k views
Original Post
RSKueffner
RSKueffner
Howdy; I often lurk the website, though not often the forums. Nonetheless, I am familiar with operator overloading. If I have an implementation of a Matrix Class for example, how would I go about being able to do the following: Matrix( I, J ) = 8; [Edited by - RSKueffner on January 30, 2009 10:45:53 AM]
SiCrane
SiCrane
In what language?
RSKueffner
RSKueffner
Ha, apologies, C++. Also note that I don't need the code, just the syntax to write the code.
SiCrane
SiCrane
struct Matrix {  int & operator()(int i, int j) { /* stuff */ }};
Cornstalks
Cornstalks
Something like:

float& operator ()(int i, int j){    return matrix[j];|


In case my example contains errors, here is a reference.

[edit]

Gaaah! SiCrane, you're crazy fast!

ninja'd++;

[edit edit]

Just so you know RSKueffner, code tags are written as either:

[source][/source]

or

[code]

or, for one liners or embedded code, I like to use



[Edited by - MikeTacular on January 28, 2009 11:09:49 PM]
RSKueffner
RSKueffner
Wow, thanks for the quick responses. Now, would that be overloading the assignment operator, or the parenthesis?

The idea is I want the following:

cout << InstanceName( I, J ) << endl; //InstanceName( I, J ) returns the value of I, J


whereas

InstanceName( I, J ) = Value; // Assigns the data of Value to InstanceName( I, J )


Note: Again each instance is of the Matrix class for example. Thanks
SiCrane
SiCrane
Overloading operator() causes your object to be treated as a function object so that you can use () on instances of the object. Returning a reference to the matrix cell allows it to be used as an lvalue, which allows both reading and writing to the referenced cell.
SiCrane
SiCrane
Quote:
Original post by MikeTacular
roflmao haha! Did you and Fruny make all those?

Many, many moons ago, there was a lounge thread about making a card game out of the gamedev.net forums. Many of the forum regulars got a card made about them. Quite a large number of forum denizens participated in it.
visitor
visitor
One thing about indexing operators (which it essentially is here) is that you provide two versions, non-const and const.

struct Matrix {  int & operator()(int i, int j) { /* stuff */ }  const int& operator() (int i, int j) const { /* same stuff */ } };


Now, if you have a const object you can still use it to read the value but not on the left side of the assignment operator:

void foo(const Matrix& m){    cout << m(i, j) << '\n'; //still works    m(i, j) = 10; //compiler error}


Without the const version the cout line would produce an error too, although it is perfectly OK to do with a non-modifiable object (assuming the overloaded operator doesn't modify the object).
RSKueffner
RSKueffner
Okay, okay. Thank you. I was originally thinking of a function returning by reference but didn't want the end programmer to have to use pointers based on context. Nonetheless, thank you.
SiCrane
SiCrane
Quote:
Original post by RSKueffner
but didn't want the end programmer to have to use pointers based on context.

I have no idea what you mean by that. References aren't pointers and don't force you to use pointers.
RSKueffner
RSKueffner
A references refers to the memory address whereas a pointer refers to the data in said address, no? If such the case, having a single function return a memory address I could assign a value to that memory address. If I wanted to use the same function as an accessor I would need to use a pointer on that memory address.

Or am I madly confused?
SiCrane
SiCrane
You're confused. I think you have pointers and references reversed.
RSKueffner
RSKueffner
So for clarification, a pointer 'points' to a memory address, the location of allocated memory for the data whereas a reference refers to the data itself?

EDIT: Nevermind. It so seems a pointer is a variable that refers to another variables memory address whereas a reference to a variable refers to that variables memory address, correct? If not please leave a short definition of each. I am nonetheless still google-ing.
visitor
visitor
A pointer is a variable holding the address of some object. A reference can be thought of as the same object, just under a different name.

#include <iostream>struct X{    char buffer[128];};int main(){    X x;    X& r_x = x;    std::cout << sizeof(x) << ' ' << sizeof(r_x) << '\n';    std::cout << &x << ' ' << &r_x << '\n';}
RSKueffner
RSKueffner
Quote:
Original post by visitor
One thing about indexing operators (which it essentially is here) is that you provide two versions, non-const and const.

*** Source Snippet Removed ***

Now, if you have a const object you can still use it to read the value but not on the left side of the assignment operator:

*** Source Snippet Removed ***

Without the const version the cout line would produce an error too, although it is perfectly OK to do with a non-modifiable object (assuming the overloaded operator doesn't modify the object).


Just as a note. I ended up using pointers so I can resolve whether or not the parameters passed fall within bound of the arrays. Now, using pointers I didn't need the const version. Intrigued by this I tried it again just returning MatrixA. Didn't need const version still. Is it just good programming practice than, or is this just an excess function definition?

template<typename DataType>DataType & Matrix<DataType>::operator( )( unsigned int I, unsigned int J ){    DataType *ReturnValue = 0;    if ( I < Height )    {        if ( J < Width )        {            ReturnValue = &MatrixA[J];        }        else //if ( J !< Width )        {            std::cerr << "J must reside on the open interval [ 0, " << Width-1 << " ]" << std::endl;        }    }    else //if ( I !< Height )    {        std::cerr << "I must reside on the open interval [ 0, " << Height-1 << " ]" << std::endl;    }    return *ReturnValue;}
rip-off
rip-off
You need the const versions for code like this to compile.
float foo(const Matrix<float> &matrix){    return matrix(0,0);}
Zakwayda
Zakwayda
Quote:
Original post by RSKueffner
Quote:
Original post by visitor
One thing about indexing operators (which it essentially is here) is that you provide two versions, non-const and const.

*** Source Snippet Removed ***

Now, if you have a const object you can still use it to read the value but not on the left side of the assignment operator:

*** Source Snippet Removed ***

Without the const version the cout line would produce an error too, although it is perfectly OK to do with a non-modifiable object (assuming the overloaded operator doesn't modify the object).


Just as a note. I ended up using pointers so I can resolve whether or not the parameters passed fall within bound of the arrays. Now, using pointers I didn't need the const version. Intrigued by this I tried it again just returning MatrixA. Didn't need const version still. Is it just good programming practice than, or is this just an excess function definition?

*** Source Snippet Removed ***
You don't want to do that. In C++, the result of dereferencing a null pointer is undefined, and generally speaking you should steer well clear of any possible undefined behavior when programming in C++.

You can assert or throw an exception if the input indices are out of bounds, but one way or another you need to return a valid reference. If you really wanted to you could return a reference to a 'dummy' static variable of some sort, but I think it's more typical just to throw or assert if there's an error.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.