I've got class with overloaded [] and I need to make it to recognize, when I try to set the values to the array. I assume, that I'll have to overload the operator =, nevertheless I don't know, how shall that whole stuff look like. Part of my code:
class Matrix {
public:
Matrix(int x, int y);
~Matrix(void);
Matrix& operator =(const Matrix &matrix); //ok...this is probably wrong...
class Proxy {
public:
Proxy(double* _array) : _array(_array) {
}
double &operator[](int index) const {
return _array[index];
}
private:
double* _array;
};
Proxy operator[](int index) const {
return Proxy(_arrayofarrays[index]);
}
Proxy operator[](int index) {
return Proxy(_arrayofarrays[index]);
}
int x, y;
double** _arrayofarrays;
};
So I just need to be able to recognize when I try to set Matrix matrix(3,3); matrix[0][0]=1;
Everything else works allright, so I assumed that it's not needed to paste the whole code
It looks like you want something which is not directly possible: operator[][].
You can emulate the behavior of this by using an intermediate class:
Since a Matrix class is typically indexed as [rows][columns], you can
have the first operator method return the corresponding Row object.
The row class can than overload the operator[] and return the corresponding
element.
Row& Matrix::operator[](int r);
double& Row::operator[](int c);
Now when you create your matrix object, you can index it as expected:
Matrix matrix(3,3);
matrix[0][0] = 1;
The last line is then equivalent to calling:
matrix.operator[](0).operator[](0) = 1;
To check for out-of-bounds indices, store the matrix sizes:
Proxy operator[](int index) {
assert(index < num_rows);
return Proxy(_arrayofarrays[index]);
}
double &operator[](int index) const {
assert(index < num_cols);
return _array[index];
}
As Aldo suggeested, Proxy can be passed the array length value in it's constructor:
Proxy(double* _array, int _length) : _array(_array), num_cols(_length){
}
As a general rule of thumb, if you're passing a raw array to a function, you will almost always want to pass the length of that array as well.
Your Proxy::operator[] overload is returning a double&. This double& is the object that will eventually be assigned to by client code, and you can't intercept that (at least not easily). Probably what you need to do is to check the index parameter in your operator[] overloads, and throw your own exception there rather than passing that index along to your internal arrays.
Related
I have class CMatrix, where is "double pointer" to array of values.
class CMatrix {
public:
int rows, cols;
int **arr;
};
I simply need to access the values of matrix by typing:
CMatrix x;
x[0][0] = 23;
I know how to do that using:
x(0,0) = 23;
But I really need to do that the other way. Can anyone help me with that?
At the end I did it this way...
class CMatrix {
public:
int rows, cols;
int **arr;
public:
int const* operator[]( int const y ) const
{
return &arr[0][y];
}
int* operator[]( int const y )
{
return &arr[0][y];
}
....
You cannot overload operator [][], but the common idiom here is to use a proxy class, i.e. overload operator [] on your Matrix class to return an instance of a different class which then has operator [] overloaded on it.
For example:
class CMatrix {
public:
class CRow {
friend class CMatrix;
public:
int& operator[](int col)
{
return parent.arr[row][col];
}
private:
CRow(CMatrix &parent_, int row_) :
parent(parent_),
row(row_)
{}
CMatrix& parent;
int row;
};
CRow operator[](int row)
{
return CRow(*this, row);
}
private:
int rows, cols;
int **arr;
};
There is no operator[][] in C++. However, you can overload operator[] to return another structure, and in that overload operator[] too to get the effect you want.
You can do it by overloading operator[] to return an int*, which is then indexed by the second application of []. Instead of int* you could also return another class representing a row, whose operator[] gives access to individual elements of the row.
Essentially, subsequent applications of operator[] work on the result of the previous application.
If you create a matrix using Standard Library containers, it's trivial:
class Matrix {
vector<vector<int>> data;
public:
vector<int>& operator[] (size_t i) { return data[i]; }
};
Some support for this has been added for containers in C++23: Multidimensional subscript operator
Although the syntax used is v[x, y, z] rather than v[x][y][z].
You could operator[] and make it return a pointer to the respective row or column of the matrix.
Because pointers support subscripting by [ ], access by the 'double-square' notation [][] is possible then.
Other answers tell you how you can do it, but...
Don’t do that.
Instead, overload operator ().
int & operator () ( size_t row, size_t col )
{
// maybe validate `row` and `col` first?
return arr[row * cols + col];
}
Why not?
The C++ FAQ explains it all. Straight from the horses’ mouths.
How do I create a subscript operator for a Matrix class?
Why shouldn’t my Matrix class’s interface look like an array-of-array?
I still don’t get it. Why shouldn’t my Matrix class’s interface look like an array-of-array?
tl;dr : encapsulation and safety
I'm learning C++, so please be patient with me.
I have a std::valarray in which there are double elements and I consider it as a 2D matrix.
class Matrix {
valarray<double> elems;
int r, c;
public:
/* type? operator[](int r) { return ? } */
//...
}
I want to overload the operator[], so that I can get a row of the matrix, and after that, I want have the m[r][c] access operator.
Is there any way to get a row, as a sequence of double using std::slice in the valarray, so that if I change a value, it is changed also in the matrix?
I've read this definition in valarray:
std::slice_array<T> operator[]( std::slice slicearr );
My operator[] must have std::slice_array<double>& as returned type?
Thanks.
I don't think std::slice and std::slice_array is what you're looking for, especially the latter is nothing but a helper type with a very limited public interface. You can instead return an proxy object. Here's a possible example of how to implement that.
class Matrix {
/* ... */
class RowProxy {
public:
RowProxy(std::valarray<double>& elems, int c, int row) :
elems(elems), c(c), row(row) {}
double& operator[](int j)
{
return elems[row*c + j];
}
private:
std::valarray<double>& elems;
int row;
int c;
};
RowProxy operator[](int i)
{
return RowProxy(elems, c, i);
}
};
This way, you can access the data with two operator[].
Matrix m(2, 4); // Assuming the ctor initializes elemens with row*column
m[0][0] = 1.234;
m[1][0] = 2.234;
m[1][3] = -52.023;
Note that both Matrix and RowProxy are missing overloads and proper handling for const-ness, and variable names are poor. Also, you might want to think about an out-of-bounds error handling strategy. But it may serve as a starting point for your implementation.
I have an existing class, which is structured in the following way:
class Matrix
{
public:
float Data[4][4];
// ... methods
};
And subsequently used in the following ways:
Matrix m;
m.Data[0][0] = 1.0f;
float local = m.Data[0][0];
//...
I would like to replace the Data member with an overloaded indexing operator, so I can perform range checking on the indices used. While I can change the Matrix class itself, and the implementations of its member functions, I cannot modify its usages in existing code, so any solution requires that the usage syntax remains identical. It's also desirable that the solution doesn't change sizeof(Matrix). Is there a way to achieve this?
Generally for this sort of thing, you need to use a proxy class to handle the second indexing operator. It would look something like this and go in the private section of your Matrix class. I'll leave out the bounds-checking (it shouldn't be hard for you to add that yourself).
class Proxy {
Matrix& ref;
size_t i;
public:
Proxy(Matrix& on, size_t i) : ref(on), i(i) {}
float operator[] (size_t j) {
return ref.Data[i][j];
}
};
Then just have your Matrix::operator[] return an instance of this class:
Proxy operator[] (size_t i) {
return Proxy(*this, i);
}
Note that if you want a const overload (ie, you want to use the indexing operator on const Matrix objects), you'll need a separate ConstProxy class which has const Matrix& ref instead of Matrix& ref but is otherwise identical.
There is also the option of returning a reference to an array. (Note: as one of the comments pointed out, this doesn't help much with bound-checking, but I think it's interesting, so I'll leave it here.)
float (&operator[](size_t i))[4] {
return Data[i];
}
The syntax for that is quite arcane, and I believe it doesn't work in Visual Studio 2013, but you can make it a bit cleaner with a typedef.
using Proxy = float[4];
Proxy& operator[](size_t i) {
return Data[i];
}
There's one more option, if you don't mind abandoning square-bracket indexing. You can overload the function call operator like this:
float operator()(size_t i, size_t j) {
return Data[i][j];
}
Another way is define a the proxy class with the semantic of a vector
class Matrix
{
public:
struct SubMatrix
{
class Vector
{
public:
Vector(float *data) : Data(data) {}
float &operator[](int index) { return Data[index]; }
private:
float *Data;
};
Vector operator[](int index)
{
return Vector(Data[index]);
}
float Data[4][4];
};
SubMatrix Data;
// ... methods
};
Then you can use it this way:
Matrix m;
float f = m.Data[1][2];
I have class CMatrix, where is "double pointer" to array of values.
class CMatrix {
public:
int rows, cols;
int **arr;
};
I simply need to access the values of matrix by typing:
CMatrix x;
x[0][0] = 23;
I know how to do that using:
x(0,0) = 23;
But I really need to do that the other way. Can anyone help me with that?
At the end I did it this way...
class CMatrix {
public:
int rows, cols;
int **arr;
public:
int const* operator[]( int const y ) const
{
return &arr[0][y];
}
int* operator[]( int const y )
{
return &arr[0][y];
}
....
You cannot overload operator [][], but the common idiom here is to use a proxy class, i.e. overload operator [] on your Matrix class to return an instance of a different class which then has operator [] overloaded on it.
For example:
class CMatrix {
public:
class CRow {
friend class CMatrix;
public:
int& operator[](int col)
{
return parent.arr[row][col];
}
private:
CRow(CMatrix &parent_, int row_) :
parent(parent_),
row(row_)
{}
CMatrix& parent;
int row;
};
CRow operator[](int row)
{
return CRow(*this, row);
}
private:
int rows, cols;
int **arr;
};
There is no operator[][] in C++. However, you can overload operator[] to return another structure, and in that overload operator[] too to get the effect you want.
You can do it by overloading operator[] to return an int*, which is then indexed by the second application of []. Instead of int* you could also return another class representing a row, whose operator[] gives access to individual elements of the row.
Essentially, subsequent applications of operator[] work on the result of the previous application.
If you create a matrix using Standard Library containers, it's trivial:
class Matrix {
vector<vector<int>> data;
public:
vector<int>& operator[] (size_t i) { return data[i]; }
};
Some support for this has been added for containers in C++23: Multidimensional subscript operator
Although the syntax used is v[x, y, z] rather than v[x][y][z].
You could operator[] and make it return a pointer to the respective row or column of the matrix.
Because pointers support subscripting by [ ], access by the 'double-square' notation [][] is possible then.
Other answers tell you how you can do it, but...
Don’t do that.
Instead, overload operator ().
int & operator () ( size_t row, size_t col )
{
// maybe validate `row` and `col` first?
return arr[row * cols + col];
}
Why not?
The C++ FAQ explains it all. Straight from the horses’ mouths.
How do I create a subscript operator for a Matrix class?
Why shouldn’t my Matrix class’s interface look like an array-of-array?
I still don’t get it. Why shouldn’t my Matrix class’s interface look like an array-of-array?
tl;dr : encapsulation and safety
it is possible to overload somehow operator for multidimensional array?
Something like:
class A {
...
int& operator[][] (const int x, const int y);
...
}
Nope, that is not possible. There are two alternatives, though:
You can have operator[] return an array of a smaller dimension (For a 3D array, it will return a 2D array, for a 2D array it will return a 1D array, and for a 1D array, it will return a single element). Then you can "string them together" with the syntax you want. (arr[x][y][z])
Alternatively, you can overload operator(), because that can take multiple arguments.
Then you can use it like this, to index into a 3D array for example: arr(x,y,z)
But you can't overload [][] or [][][] as a single operator.
Not directly, but you can achieve the same functionality overloading operator[]() and having it return something that supports operator[]() itself.
For example:
class A {
std::vector<std::vector<int> > vec;
public:
std::vector<int>& operator[] (int x)
{
return vec[x];
}
};
would allow you to write:
A a;
//...
int y = a[1][2];
because a[1] returns a std::vector<int> to which you can apply operator[](2).
You need to overload operator[] and make it return a new class which only has another operator[].
No, there's just operator[]. As an alternative, you can overload:
int &operator()(int x, int y);
You can use that:
m(4, 5);
Since C++23, an overloaded operator[] will now take 0 or more arguments which behaves exactly the same as operator()
class A {
// ...
int& operator[](std::size_t x, std::size_t j);
// ...
};
invocation:
A a = /* ... */;
a[1, 2]; // equivalent to 'a.operator[](1, 2)'
It is a single operator being used twice to dereference. You can dereference [] operator and perform the functionality and usage by using it as [][] by changing the return type.
There's no operator like that. I implemented, some times ago, a matrix trying to be close to the stl standards.
And I used this method: first I've overloaded the operator[] to return another class that I called _C_row:
_C_row operator[](size_type index) { return _C_row(/*some parameters*/); } ///< This operator is overloaded to permit the use of double pointer notation.
_C_row operator[](size_type index) const { return _C_row(/*some parameters*/); } ///< This operator is overloaded to permit the use of double pointer notation.
And in _C_row I overloaded more than the operator[]:
value_type operator*() { return _r[0]; }
pointer operator->() { return _i[_idx]; }
double_pointer operator&() { return &(_i[_idx]); }
reference operator[](size_type col) { return _r[col]; }
const_reference operator[](size_type col) const { return _r[col]; }
I found this solution is very flexible. I hope my answer could be useful for you.
As mentionned before, there is no such thing as operator[][].
However, here is an an implementation using nested classes similar to what "jalf" proposed. For sake of simplicity, I hardcoded a 3x3 raw array.
class Array2D final{
public:
class PartialArr final{
private:
friend Array2D;
PartialArr(Array2D* ptr, int index) :original(ptr), firstIndex(index) {}
int firstIndex;
Array2D* original;
public:
int& operator[](int index) { return this->original->data[firstIndex][index]; }
};
PartialArr operator[](int index) { return PartialArr(this, index); }
private:
int data[3][3];
};
This solution prevents the user of Array2D to manipulate the data directly when indexing only the first dimension of the array.
const versions of both operator[] could also be added to make the class complete.