BTW: I am seeking to answer the parts of this question as asked. I am also not seeking to replicate all the information in other worthy answers. The bounty seeks something different to the question as asked, so I am not responding to that.
It is actually fairly simple to provide a matrix multiplication. Since I'm not proposing to describe data structures to represent a matrix and fully implement operations and validity checks on them, I'll just provide skeletons to illustrate.
Example 1: operator*()
as a member function
class M // a basic matrix class
{
public:
// assume other constructors and members to set things up
M operator*(const M &rhs) const;
};
M M::operator*(const M &rhs) const
{
// implement checks on dimensions, throw an exception if invalid
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
int main()
{
M a;
M b;
// set up elements of a and b as needed
M c = a*b; // this relies on M having appropriate constructor(s) to copy or move the result of a*b into c
M d;
d = a * b; // this relies on M having appropriate operator=() to assign d to the result of a*b
}
The above implements operator*()
as a member function. So, functionally, c = a*b
is equivalent to c = a.operator*(b)
. The const
qualifiers represent the fact that a matrix multiplication a*b
does not generally change a
or b
.
Example 2: operator*()
as a non-member function
Now, operator*()
can also be implemented as a non-member (optionally a friend
), with a skeleton that looks like
class M // our basic matrix class, different operator *
{
public:
// assume other constructors and members to set things up
friend M operator*(const M &lhs, const M &rhs);
};
M operator*(const M &lhs, const M &rhs)
{
// implement checks on dimensions, throw an exception if invalid
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
// same main() as before
Note that, in this case, a*b
is now equivalent to operator*(a, b)
.
If you want to use both forms, care is needed to avoid ambiguity. If both forms of operator*()
are provided they are both valid matches in a statement like c = a*b
and the compiler has no means to choose one form over the other. The result is code not compiling.
Example 3: overloading operator*()
It is also possible to overload operator*()
- for example, to multiply a matrix by a scalar.
class M // a basic matrix class
{
public:
// assume other constructors and members to set things up
M operator*(const M &rhs) const; // as in first example
M operator*(double scalar) const; // member form
friend M operator*(double scalar, const M &rhs); // non-member form
};
M M::operator*(double scalar) const
{
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
M operator*(double scalar, const M &m)
{
M result;
// implement the multiplication (typical iterations) and store results in result
return result;
}
int main()
{
M a;
M b;
// set up elements of a and b as needed
M c = b * 2.0; // uses the member form of operator*() above
M d;
d = 2.0*a; // uses the non-member form of operator*() above
}
In the above b*2.0
amounts to a call of b.operator*(2.0)
and 2.0*a
to a call of the non-member operator*(2.0, a)
. The member forms can only generally be used in expressions where the left hand operand is of type M
. So 2.0*a
will not work if only member forms of operator*()
is provided.
Discussion
Apart from concerns of ambiguity above, there are other things to be aware of when overloading operators.
- It is not possible to change precedence or associativity of operators from their specification in language rules. So, in the expression
a+b*c
, the *
will always have higher precedence than the +
. This is also the reason it is not a good idea to overload ^
for exponentiation in C++, since ^
has a lower precedence than +
in C++ (being a bitwise operation on integral types). So a + b^c
is actually equivalent in C++ to (a + b)^c
, not to a + (b^c)
(which anyone with basic knowledge of algebra would expect).
- The language specifies a set of operators, and it is not possible to create new ones. For example, there is no
**
in C++, such that a ** b
raises a
to the power of b
(which other languages can do), and it is not possible to create one.
- Not all operators can be overloaded.
One of the operators that cannot be overloaded in C++ is .*
. So it is not possible to use such an operator like you would in Matlab. I would generally suggest NOT trying to get the same effect using other operators, because the above constraints will affect that (and cause expressions to give counter-intuitive behaviour). Instead simply provide another named function to do the job. For example, as a member function
class M
{
public:
// other stuff
M ElementWiseProduct(const M &) const;
};