I'm building a Matrix class for all the operations such as addition, subtraction, multiplication, inverse etc. I have overloaded simple operators such as + - () *. But I'm trying to set a row and column value via ().
A sample would be like so
Matrix(1,1) = 10;
assuming that row 1, column 1 would be set to 10.
A sample of my addition overload is this
friend Matrix operator +(Matrix&, Matrix&);
How can I achieve this?
Thanks!
Your matrix should provide element accessors, e.g. via operator():
template <typename T>
class Matrix
{
public:
T & operator()(size_t i, size_t j) { return buf[i * NCols + j]; } // Example
T const & operator()(size_t i, size_t j) const { /* same */ }
// ...
};
Then you can say:
Matrix<bool> m(20, 20);
m(12, 15) = false;
m(8, 19) = m(1, 2) = true;
return m(0, 0);
It's similar to what you've done already:
Value &operator()(int x, int y)
{
return matrix[x][y]; // or whatever it's supposed to be
}
, where Value is your internal type.
However, I suggest instead using a setter function, since it is far less ambiguous. e.g.:
void set(int x, int y, Value v)
{
matrix[x][y] = v;
}
Use
class Matrix {
T& operator()(size_t x, size_t y) {
return _mat[x][y]; //Or however your datastructure works
}
const T& operator() (size_t x, size_t y) const {
return _mat[x][y];
}
};
Where T is the datatype your matrix holds. Return the data at (x,y).
Related
I'm trying to make a Matrix struct which would work with various data types, including my Complex struct:
struct Complex {
double re = 0, im = 0;
Complex operator*(const Complex& other) const {
return Complex(re * other.re - im * other.im, im * other.re + re * other.im);
}
Complex operator*(const double& other) const {
return Complex(re * other, im * other);
}
Complex() {}
Complex(double a) : re(a) {}
Complex(double a, double b) : re(a), im(b) {}
};
std::ostream& operator<<(std::ostream& out, Complex z) {
out << z.re << " " << z.im << "i";
return out;
}
template <typename T>
Complex operator*(const T& c, const Complex& z) {
return z * c;
}
The obvious way is to make a template like one in the code below:
template <typename T>
struct Matrix {
std::vector<T> m;
unsigned int rows, cols;
Matrix<Complex> operator*(const Complex& z) const {
Matrix<Complex> result(rows, cols);
for (int i = 0; i < m.size(); i++) {
result.m[i] = m[i] * z;
}
return result;
}
void operator*=(const Complex& z) {
(*this) = (*this) * z; // <- ideally we're trying to get this to work
}
void operator=(const Matrix<T>& other) {
rows = other.rows;
cols = other.cols;
m.resize(rows * cols);
m = other.m;
}
Matrix(const unsigned int& rows, const unsigned int& cols) : rows(rows), cols(cols) {
m.resize(rows * cols);
}
Matrix(const Matrix<T>& other) : rows(other.rows), cols(other.cols) {
(*this) = other;
}
};
int main() {
Complex z(1, 1);
Matrix<double> A(1, 1);
A.m[0] = 2.0;
std::cout << (A * z).m[0] << std::endl; // works as it should because a temporary Matrix<Complex> gets created
A *= z; // and here we're introducing the problem
std::cout << A.m[0] << std::endl;
}
The problem arises when calling *= operator. We're trying to call an unexisting = operator overload. My first attempt was to write something like this instead:
template <typename T_other>
void operator=(const Matrix<T_other>& other) {
rows = other.rows;
cols = other.cols;
m.resize(rows * cols);
for (int i = 0; i < m.size(); i++) {
m[i] = other.m[i];
}
}
This however leads to other problems:
The type of A is still Matrix<double> and after the multiplication it should be Matrix<Complex> to store complex numbers.
There is no conversion from Complex to double as it results in loss of data (the imaginary part).
Also, I would like to avoid creating a template specialization for Matrix<Complex>, but if there's no other way I'll accept it.
C++ is statically typed. Once you declare a variable and type, you can't change the type of that variable.
template <typename T>
struct Matrix {
void operator*=(const Complex& z) {
(*this) = (*this) * z;
}
}
The *= operator overload for your Matrix doesn't make sense. A Complex can hold the value of a double with imaginary part 0, but a double can never hold the value of a Complex.
Multiplying a real matrix by a complex number necessarily produces a complex matrix. So you try and assign the complex RHS to the real LHS - and either that makes no sense and shouldn't be done, or you have some idea for how to convert that (e.g. keep real part, keep absolute value etc) and then have to implement a Matrix<double> constructor from Matrix<Complex>.
Real numbers are a subset of complex numbers, so just make A a Matrix<Complex> from the beginning if you ever want to make it complex later.
I have the following code:
template<size_t rows, size_t cols>
class Matrix{
std::array<int, rows * cols> data;
public:
int operator()(size_t i, size_t j){
return data[i * cols + j];
}
// ...code...
}
What is the best way to achieve this:
Matrix<1,1> a;
a(0, 0) = 0;
avoiding the lvalue required as left operand of assignment error?
You can change the following line:
int operator()(size_t i, size_t j){
To:
int & operator()(size_t i, size_t j){
Returning a refernce (L value reference to be precise) to the element in the Matrix will allow you to assign to it.
Update: Some notes to complete my answer:
As #user4581301 commented: you can see more info about C++ value categories here: What are rvalues, lvalues, xvalues, glvalues, and prvalues?
As #Darth-CodeX and #HolyBlackCat mentioned, it is advisable to add a const overload for operator():
int const & operator()(int i, int j) const { /* same implementation */ }
You can use it with a const Matrix for reading elements values: if you have e.g. a Matrix const & m, you can use int val = m(0,0) to read an element value (of cource you will not be able to use it for assignment due to constness).
You need to return the reference of the element from data like this:
// can change
int &operator()(size_t i, size_t j)
{
return data[i * cols + j];
}
And every STL container includes a const function, for the cases like const Matrix &
// cannot change
int operator()(size_t i, size_t j) const
{
return data[i * cols + j];
}
Why do it twice?
These 2 lines, why do it like this way? Is one enough?
inline T& operator() (int row, int col) { return this->m_data[row*NC + col]; }
const inline T& operator() (int row, int col) const { return this->m_data[row*NC + col]; }
thank you
*
* 2-DIMENSIONAL ARRAY
*
* Simulated by 1-dimension array.
******************************************************************************/
#ifndef __2D_ARRAY_H__
#define __2D_ARRAY_H__
#include <stdint.h>
#include <stdlib.h>
namespace alg {
/**
* 2D Array definition
*/
template <typename T=char>
class Array2D {
private:
uint32_t NR; // num of rows
uint32_t NC; // num of columns
T * m_data; // the place where the array resides.
public:
/**
* construct an array of size [nrow,col]
*/
Array2D(uint32_t nrow, uint32_t ncol) {
NR = nrow;
NC = ncol;
m_data = new T[nrow*ncol];
}
/**
* destructor
*/
~Array2D() {
delete [] m_data;
}
private:
Array2D(const Array2D&);
Array2D& operator=(const Array2D&);
public:
/**
* return number of rows of this array
*/
inline const uint32_t row() const { return NR; }
/**
* return number of columns of this array
*/
inline const uint32_t col() const { return NC; }
/**
* return the value by the given (row, col);
*/
inline T& operator() (int row, int col) { return this->m_data[row*NC + col]; }
const inline T& operator() (int row, int col) const { return this->m_data[row*NC + col]; }
inline T* operator[] (int row) { return &(m_data[row * NC]); }
inline const T* operator[] (int row) const { return &(m_data[row * NC]); }
/**
* clear the array by a given value
*/
void clear(const T & value) {
for(uint32_t i=0; i<NR*NC;i++){
m_data[i] = value;
}
}
};
}
#endif //
One is const and the other is not.
The difference is that when you have a const reference to a Array2D you're only allowed to call member functions marked const. In this case that means the 2nd version, where it must necessarily return a const reference to the element it holds.
If you have a non-const reference, though, that 2nd version means you can't use operator() to make any changes to your Array2D.
If you look at standard library containers like std::vector you'll see that they do the same thing. You can get an iterator from begin() and a const_iterator from begin() const.
The first, non-constant version returns a reference that can be modified. If you have a constant object, you still want to be able to at least read the value, so you have to provide a second constant version.
The two () operators are not the same. inline T& operator() (int row, int col); returns a reference that allows the returned value to be modified. const inline T& operator() (int row, int col) const returns a reference that disallows the returned value from being modified. Also if the calling object is a const alg::Array2D&, than it can ONLY use the const operator();. So in order to allow users of the Array2D class to properly use const objects. It is best practice to implement both signatures for the operator ().
You could have a function void make_something (const Array2D<char> &input, Array2D<char> &output). This function lets input untouched, makes some operation with it, and writes the result to output. Reading from input would only be possible if there is also a const operator.
inline T& operator() (int row, int col) { return this->m_data[row*NC + col]; }
returns a non-const reference to the data in m_data[row * NC + col], which means I can do
auto& ref = obj(x, y);
ref = BAD_DATA;
and your object can't stop me. The const variant protects against this, and can be fingerprinted as const because it has no side effects on the object as a result.
inline const T& operator() (int row, int col) const { return this->m_data[row*NC + col]; }
This allows me to propagate constness outwards:
void myFunc(const Object& obj) /* I'm only going to look */
{
const auto& ref = obj(x, y);
std::cout << x << ',' << y << " = " << ref << '\n';
}
Suppose we have class name Default that have two attribute x and y.
The default operation to compare object is using attribute x.
When we would like to compare this object using other attribute y,
1. Is it safe to create new derive class that can compare by using attribute y and then casting pointer from Default to that new class and compare object?
2. What is alternative way to do this without decreasing the performance of operation?
The requirement is we can not change the the signature of sorting algorithm to pass on function pointer to difference comparator.
By the way this method is required no cost for convert or copy data.
class Default {public:int x; int y;};
class Compare1 : public Default {};
bool operator < (const Default &left,const Default &right)
{
return left.x < right.x;
}
bool operator < (const Compare1 &left,const Compare1 &right)
{
return left.y < right.y;
}
template<typename T>
int *sort_element(const T *data, int size)
{
int *permute;
//... do some sorting by using < comparator ...
return permute;
}
int main(){
Default *obj;
int obj_size;
//… initialize obj and obj size..
// sorting object with default order.
int *output_default = sort_element(obj, obj_size)
// sorting with customize comparator.
Compare1 *custom1 = static_cast<Compare1*>(obj);
int *output_custom1 = sort_element(custom1, obj_size);
}
Better is passing a functor or lambda as compare function when you're sorting them. Your sort function must accept a function:
template<typename T, typename F>
int *sort_element(const T *data, int size, F comp)
{
....
if (comp(a, b))
....
...
}
Then
// Sort by x
sort_element(..., [](const Default &a, const Default &b) {
return a.x < b.x;
});
// Sort by y
sort_element(..., [](const Default &a, const Default &b) {
return a.y < b.y;
});
If you haven't C++11 you can use function object (functor) instead:
struct fx
{
bool operator()(const Default &a, const Default &b) const
{
return a.x < b.x;
}
};
struct fy
{
bool operator()(const Default &a, const Default &b) const
{
return a.y < b.y;
}
};
// Sort by x
sort_element(..., fx());
// Sort by x
sort_element(..., fy());
Forget your second class Compare1 and Remove it.
I, like so many programmers before me, am tearing my hair out writing the right-of-passage-matrix-class-in-C++. I have never done very serious operator overloading and this is causing issues. Essentially, by stepping through
This is what I call to cause the problems.
cMatrix Kev = CT::cMatrix::GetUnitMatrix(4, true);
Kev *= 4.0f;
cMatrix Baz = Kev;
Kev = Kev+Baz; //HERE!
What seems to be happening according to the debugger is that Kev and Baz are added but then the value is lost and when it comes to reassigning to Kev, the memory is just its default dodgy values. How do I overload my operators to allow for this statement?
My (stripped down) code is below.
//header
class cMatrix
{
private:
float* _internal;
UInt32 _r;
UInt32 _c;
bool _zeroindexed;
//fast, assumes zero index, no safety checks
float cMatrix::_getelement(UInt32 r, UInt32 c)
{
return _internal[(r*this->_c)+c];
}
void cMatrix::_setelement(UInt32 r, UInt32 c, float Value)
{
_internal[(r*this->_c)+c] = Value;
}
public:
cMatrix(UInt32 r, UInt32 c, bool IsZeroIndexed);
cMatrix( cMatrix& m);
~cMatrix(void);
//operators
cMatrix& operator + (cMatrix m);
cMatrix& operator += (cMatrix m);
cMatrix& operator = (const cMatrix &m);
};
//stripped source file
cMatrix::cMatrix(cMatrix& m)
{
_r = m._r;
_c = m._c;
_zeroindexed = m._zeroindexed;
_internal = new float[_r*_c];
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] = m._internal[i];
}
}
cMatrix::~cMatrix(void)
{
delete[] _internal;
}
cMatrix& cMatrix::operator+(cMatrix m)
{
return cMatrix(*this) += m;
}
cMatrix& cMatrix::operator*(float f)
{
return cMatrix(*this) *= f;
}
cMatrix& cMatrix::operator*=(float f)
{
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] *= f;
}
return *this;
}
cMatrix& cMatrix::operator+=(cMatrix m)
{
if (_c != m._c || _r != m._r)
{
throw new cCTException("Cannot add two matrix classes of different sizes.");
}
if (!(_zeroindexed && m._zeroindexed))
{
throw new cCTException("Zero-Indexed mismatch.");
}
for (UInt32 row = 0; row < _r; row++)
{
for (UInt32 column = 0; column < _c; column++)
{
float Current = _getelement(row, column) + m._getelement(row, column);
_setelement(row, column, Current);
}
}
return *this;
}
cMatrix& cMatrix::operator=(const cMatrix &m)
{
if (this != &m)
{
_r = m._r;
_c = m._c;
_zeroindexed = m._zeroindexed;
delete[] _internal;
_internal = new float[_r*_c];
UInt32 size = GetElementCount();
for (UInt32 i = 0; i < size; i++)
{
_internal[i] = m._internal[i];
}
}
return *this;
}
Your operators + and * must return by value, not by reference. You're returning a temporary variable by reference. Also, you're arguments are passed by value when it should be a const reference:
cMatrix cMatrix::operator+(cMatrix const& m)
{
cMatrix matrix(*this);
matrix += m;
return matrix;
}
cMatrix cMatrix::operator*(float f)
{
cMatrix matrix(*this);
matrix *= m;
return matrix;
}
You should take a look at Boost.Operators. This would let you implement only operator*= and operator+= and automatically provide correct implementations for operator+ and operator*.
PS: If you implement your matrix class just for the learning experience, don't hesitate to look at other implementations like the Matrix Template Library.
PPS: If you don't want to use boost, or if you just want to understand the best practice, take a look at Boost.Operator and do what they do.
IMO the canonical form of overloading addition is this:
class X {
public:
X& operator+=(const X& rhs) { /*add rhs to *this*/ }
};
inline X operator+(X lhs, const X& rhs) {lhs+=rhs; return lhs;}
The same goes for -, *, /, where applicable.
Note that + returns a copy, not a reference. That's important, because A+B creates a new value, so it cannot return a reference to an existing one.
Also, it is a free function. IMO it's best to implement those of the binary operators which can be implement either as a member or as a free function as free functions, if they treat their operands symmetrically (as does +), and as member functions, if they treat their operands asymmetrically (as +=, which changes its left argument. If you implement operator+ as a member, you will have to make the function const (X operator+(const X& rhs) const), so that it can be invoked for constant elements on the left side.