operator * overloading C++

Pages: 12
Apr 11, 2010 at 12:26am
Hello,

I know how to overload the * operator. But, my concern is how to implement it for a matrix class. I would like to implement both matrix multiplication and element by element (point-wise) multiplications.

thank you.
Apr 11, 2010 at 3:06am

You can declare two * operators which take different parameters One takes a matrix, and the other takes a type corresponding to the element by element type.
Apr 11, 2010 at 8:34am
I would suggest the following header.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class matrix
{
public:
  void operator=(const matrix& right)//some prefer to declare this matrix& operator=(const matrix&)
  { 
    /*...*///do your matrix assignment here
  };
  matrix (const matrix& right)
  {
    (*this)=right;
  };
  matrix operator* (const matrix& right) const 
  { 
    matrix result;
    /*write the multiplication code here to assign the final result to element result*/
    return result;
  };
};


The rest of the details you should be able to figure on your own.
Explanation of the code:
1
2
matrix a,b,c;
a=b*c;

This code will do the following. It will call b.operator*(c). At the time it reaches "return result;" it will create a new hidden (named by the compiler) element of class matrix via the constructor matrix( const matrix& right), with argument the variable result.

Let us name the invisible element m. Finally, the code will invoke a.operator=(m).

A note: with the gcc compiler, you can have the following optimization: declare the copy constructor matrix( const matrix& right); to be private and give it no body. Then gcc will not create an extra invisible object m, and will call no copy constructor; instead, it will call directly a.operator=(result), before calling the destructor of the object result. Note: this optimization is better computationally, but will fail to compile on the microsoft compiler.
Last edited on Apr 11, 2010 at 8:46am
Apr 11, 2010 at 9:13am
If you want to do that, you can always implement *= and do a=b; a*=c;.
Apr 11, 2010 at 9:34am
choisum, I guess that's the only way. We can not implement a new operator like .* in Matlab to distinguish with the operator which multiplication operation is performed on the matrix.

tition, Thanks, but I guess you misunderstood my question (and helios is right). However, I have overloaded almost all operators and had doubts of implementing the * and *= in context of "matrix" and to distinguish matrix multiplication and point-wise matrix multiplication.

thank you.

PS: While at it, I would like to ask another related question. Suppose I have a(n) (overloaded) function like this,
1
2
3
4
template <class T>
vec<T> find(const mat<T>& m, int idx, const string val) {
        ...
}

My intention is to find the first or last occurrence of a particular value idx in matrix m. So, val = "first" or val = last. But is there any possibility to assign val to first by default and by doing that, can I call the function for example as, find(m, 4) and it would get me the first occurrence of 4? Or should I implement the whole function again without the string parameter and implement it for first (default) every time?
Last edited on Apr 11, 2010 at 9:44am
Apr 11, 2010 at 10:04am
void operator=(const matrix& right)//some prefer to declare this matrix& operator=(const matrix&)

The reason returning matrix& is (or should be) preferred is so that you can compound assignments like you can with other basic types.

1
2
3
4
5
6
7
8
9
int a, b, c;

a = b = c;  // perfectly legal statement
  // same as:
  //   b = c;
  //   a = b;

matrix A, B, C
A = B = C;  // logically, this should also be legal, but it isn't if = returns void 
Last edited on Apr 11, 2010 at 10:04am
Apr 11, 2010 at 11:15am
@helios: Sure, but if you write a=b*c+d*e as

1
2
3
4
5
6
matrix a,b,c,d,e, temp;
a=b;
a*=c;
temp=d;
temp*=e;
a+=temp;

it kinda kills the purpose of operator overloading (the purpose of which is to facilitate a programmer's lazyness and to make code slightly more readable).

In fact, I managed to write my first 25k LOCs without using any operator overloading (I simply called functions such as a.MultiplyBy(b);.

This is efficient to execute and slow to write.

Edit: @Disch:
A = B = C; // logically, this should also be legal, but it isn't if = returns void

I see no logical reason why this should be legal (nor a logical reason why it shouldn't be). It is just a convention. It's use contradicts mathematical common sense and so I dislike it and declare all operator='s as void.
Last edited on Apr 11, 2010 at 11:30am
Apr 11, 2010 at 11:51am
Anybody knows the answer to my other question (in the PS)??
Apr 11, 2010 at 12:12pm
I think you should do it like this:
1
2
template <class T>
vec<T> find(const mat<T>& m, int idx, const string val="last"){/*...*/}

And then everything you desired seems to be accomplished. (It will have a default value and you can call find<int>(m,4);)
Apr 11, 2010 at 3:15pm
closed account (1yR4jE8b)
A = B = C; // logically, this should also be legal, but it isn't if = returns void

I see no logical reason why this should be legal (nor a logical reason why it shouldn't be). It is just a convention. It's use contradicts mathematical common sense and so I dislike it and declare all operator='s as void.


I really don't want to offend you tition but...

This is one of the reasons that I absolutely hate dealing with operators overloaded by other programmers. Assignment operators returning references is a C++ 'unwritten rule' and when you do things against it you really piss off people who are going to use your code.

If I'm working on a project with 30 other people and someone give me a class that has an overloaded assignment operator, I'm going to assume that I can compound statements like A = B = C because that is a convention of the rest of the language. (At my job, somebody who writes an operator incorrectly has to buy coffee for the entire office for a week.) It grinds my gears when one naive programmer thinks he's knows better than the millions of other programmers out there and writes code that doesn't work like it should because it 'makes more sense to them'. It makes less sense to write code like this because it is inconsistent with every other aspect of the language.

C++ is not a mathematical problem solving program like Matlab and Maple. Just because there are arithmetic operators and you can evaluate expressions doesn't mean you need to write code so it 'makes sense mathematically', it should 'make sense c++-ically" ;-P.
Apr 11, 2010 at 3:26pm
(At my job, somebody who writes an operator incorrectly has to buy coffee for the entire office for a week.)


I am glad I am not working at your job then. How often do you write operator overloading?

Edit. P.S. I am writing a program of the likes of Matlab and Maple to solve a particular problem; however, of course, for my specialized problem, mine is much better than Matlab and Maple.

By the way, Maple is way too buggy, I would never use it for serious research (I once had to expand some power series with it and it gave me a wrong answer. This was not acceptable! An uninstall followed ).
Last edited on Apr 11, 2010 at 3:57pm
Apr 11, 2010 at 4:16pm
closed account (1yR4jE8b)
I was exagerrating a little bit...but some newer people have messed up so badly that we decided it was appropriate to enforce the rule a couple of times ;-)
Apr 11, 2010 at 4:46pm
I'm going to assume that I can compound statements like A = B = C because that is a convention of the rest of the language


This + 1.

It's how the = operator works in the rest of the language, therefore it's how the = operator should work in any classes you write.

The whole point of operator overloading is to mimic the behavior of the operator in an intuitive fashion.

1
2
3
4
5
y = x++;  // should be the same as y = x; x++;
y = x + 5;  // should not change x
x += 5;  // should change x
x = y = z;  // should assign z to x and y  (edit:  has this worked backwards before)
// etc 


These rules should be true for ALL types. Not just for primitive types.

This is just how C++ works. This is basic, fundamental language syntax.

Overloaded operators which break these rules are poorly written.
Last edited on Apr 11, 2010 at 5:14pm
Apr 11, 2010 at 5:26pm
to mimic the behavior of the operator in an intuitive fashion


... is precisely the point where we agree with one another completely. To me, a=b=c is completely counterintuitive.

I am sure that in the beginning of C creation, it was a flip of a coin whether to allow such expressions or not. Somebody thought it's a good idea, and so it stuck to the language.

If he/she had thought like I do, and said that void operator= is better, then now people who use matrix& operator=(/*...*/) would be "not-understanding-how-c++-works" (although I wouldn't be the one telling that to anybody).
Apr 11, 2010 at 5:29pm
And what do you suggest it should do?
Apr 11, 2010 at 5:39pm
void - although I am not suggesting anything to anybody; I am saying how I use it.
Apr 11, 2010 at 7:35pm
closed account (1yR4jE8b)
It doesn't matter who won the coin toss, either decision really is valid in design...

I'm not trying to argue the fundamentals of the design, I'm just saying that's the way it is and there's no changing it. There is no point in writing things opposite of the design language, THAT is counterintutive because other people that use your code will get pissed off when something doesn't work the way the language was designed.

EDIT:

It's petty arguments like this that caused the Java devellopers to flat out leave out operator overloading from the Java specification. ;-)
Last edited on Apr 11, 2010 at 7:37pm
Apr 11, 2010 at 8:06pm
I thought it was because the designers have the "if it can be horribly misused, it doesn't belong in the language" philosophy. It's the same reason why there's no goto and preprocessor.
Last edited on Apr 11, 2010 at 8:40pm
Apr 11, 2010 at 8:46pm
There are a lot of features in C++ that are prohibiting as well. For example, const.

For the last 1/2 year it has been annoying me greatly, with one remarkable exception where it helped me find a potential problem. After changing my hash function template to int HashFunction() const; instead of int HashFunction();, I found one of my classes actually modifies *this during the computation of the hash value (which is not desirable).
Last edited on Apr 11, 2010 at 8:47pm
Apr 11, 2010 at 9:06pm
If there's only one thing C++ is innocent of is of being restrictive.
const is there only to reduce the probability of bugs arising from modifying data that wasn't supposed to be modified, and to allow declaring symbolic constants. The only instance you're forced to use it is when passing intermediate values by reference, and you can avoid that by writing them to temporary objects if you really hate const that much.
const is no more restrictive than references, which don't allow you to pass null like pointers, or RAII, which doesn't allow you to create an object and not destruct it.
C++ will never prevent you from declaring all your functions as void *make_snafucated(void *,void *,void *);, but would you really want to?
Pages: 12