Let us consider
we have created our own class Array. And now we want to overload "+" operator so that if:
Array a(5), b(3);
Array c = a + b;
it simply glues together a array and b array and we get a c array with length 5+3=8.
Now, I have realised this case writing in me Array.cpp file:
Array Array::operator+(const Array &Right)
{
Array temp_A(m_iCurInd+Right.m_iCurInd);
// here some stuff, not important to the quastion//
return temp_A;
}
And everything is fine.
But what if I want to :
Array a(5);
Array c = a + 2;
Array d = 2 + a;
So that d and c had lengths 6, with "2" in the beginning and in the end respectively?
I have tried
to realise the firs case, so in Array.h file it was such a line:
Array operator+(const int &value); //a+2
And in Array.cpp:
Array Array::operator+(const int &value)
{
Array temp_A(m_iCurInd+1);
// here some stuff, not important to the quastion//
return temp_A;
}
But it doesn't compiles, because it doesn't likes the types (particulary const int & I think). How shell I make it? Shell it be:
Array int::operator+(const Array &Right){
....
}
for the "2+a" case or something simmilar? Please advise me.
You might do this:
class Array
{
// ...
// Insert an Element
public:
void prepend(int);
void append(int);
// Append an Array
void append(const Array&);
// ...
};
inline Array operator + (const Array& a, const Array& b) {
Array result(a);
result.append(b);
return result;
}
inline Array operator + (const Array& a, int b) {
Array result(a);
result.append(b);
return result;
}
inline Array operator + (int a, const Array& b) {
Array result(b);
result.prepend(a);
return result;
}
You would define operator+ as a non-member function to support mixed-mode arithmetic.
Array operator+( const Array &arr1, const Array &arr2 )
and then provide appropriate single argument constructor for the types you want to support mixed-mode arithmetic.
To allow the syntax Array + int you have two options: Create a member function overload of operator+ where the parameter it takes is an integer, or create a free operator+ whose parameters are Array and int respectively. It looks like you've done it correctly for the member function overload, but to make sure, it should look like this:
class Array
{
// ...
Array operator+(int rhs)
{
// ...
}
};
Now Array + int should work. If it doesn't, you've done something wrong inside the function.
To allow the syntax int + Array you need a free operator function because the member function won't overload int for the left side:
Array operator+(int lhs, Array const& rhs)
{
return rhs + lhs;
}
rhs + lhs calls the member function overload Array::operator+().
Related
I am looking for overloading [] operator for a two dimensional array pointer
to access cell element.
Two dimensional array is passed to my function as int *arr.
We can access cell element by *(arr+i*N+j) where N is the column count
and i is row index and j is column index.
But can we write this like arr[i,j] or arr(i,j) for better readability
using some macro or operator overloading?
Any suggestion?
You cannot do that directly.
I would suggest to write a little class/struct that would wrap your 2D array conveniently. Here I use std::vector instead of int *arr and you do not have to care about memory management. The following code presents 3 possibles methods :
Method 1 (recommended) : accessing via mat(i,j)
The operator()(size_t i, size_t j) is called function call operator.
template<typename T>
struct Matrix
{
Matrix(const std::vector<T>& d, size_t s) : Matrix(d, s, s) {}
Matrix(const std::vector<T>& d, size_t c, size_t r) : data_(d), cols_(c), rows_(r) {}
std::vector<T> data_;
size_t cols_;
size_t rows_;
const T& operator()(size_t i, size_t j) const { return data_[i * cols_ + j]; }
T& operator()(size_t i, size_t j) { return data_[i * cols_ + j]; }
// and you can add other convenient methods
};
Use it like this :
Matrix<int> mat({1, 2, 3, 4, 5, 6, 7, 8, 9}, 3, 3); // a 3x3 matrix
std::cout << mat(1,2) << std::endl;
Live code
If you know the size at compile time then you can use std::array and change your struct accordingly :
template<typename T, size_t Cols, size_t Rows> struct Matrix
{
std::array<T, Cols * Rows> data_;
// etc...
Method 2 : accessing via mat[{i,j}]
Using the array subscript operator only takes one argument so you can change/add the following operators to your class :
const T& operator[](const std::array<size_t,2>& a) const { return data_[a[0] * cols_ + a[1]]; }
T& operator[](const std::array<size_t,2>& a) { return data_[a[0] * cols_ + a[1]]; }
which can be called like this :
std::cout << mat[{1,2}] << std::endl;
Note that this method is useful when you work on several dimensions (you do not have to write several operator()(size_t i, size_t j, size_t k, etc...)
Method 3 (not recommended) : accessing via mat[Idx(i),Idx(j)]
You can take two arguments using the array subscript operator but you have to overload the comma operator which is not possible between two built in types... So accessing directly via mat[i,j] is not possible (Thanks leemes' comment for pointing that out).
However you can create your own type and overload it. Here an example (put it before your Matrix class definition) :
struct Idx
{
Idx(size_t ii) : i(ii) {}
size_t i;
operator size_t() const { return i; } // implicit user-defined conversion
};
std::array<size_t, 2> operator , (Idx i1, Idx i2)
{
return { i1, i2 };
}
// etc...
// and we do not have to add Matrix operators since we reused the one from Method 2
Use it like this :
std::cout << mat[Idx(1),Idx(2)] << std::endl;
which is not that elegant...
Complete and final live code
You can write an index function to hide the formula.
If your N is defined globally, write
int index(int i, int j) {
return i * N + j;
}
and use it with
arr[index(i, j)]
Alternatively, write a wrapper class around your pointer. This class can be written with absolutely no runtime overhead. It can have an operator to allow the syntax
arr[i][j]
where arr is an instance of the wrapper class. Such a wrapper can be defined like this:
class Array2DWrapper {
int *ptr;
public:
Array2DWrapper(int *ptr) : ptr(ptr) {}
int * operator[](int i) {
return ptr + i*N;
}
};
// USAGE:
void exampleFunction(int *arrPtr) {
Array2DWrapper arr { arrPtr };
...
arr[i][j];
...
}
As you can see, the idea is to overload operator[] for the outer dimension, which returns a pointer to the inner dimension. When the user of this class writes arr[i], it calls the custom operator overload, which returns an int*, then the next [j] accesses the element using the builtin operator[] for pointers.
Note that the above class can be used as a function parameter, but the caller can call it with a raw pointer to some 2D array. This will call the constructor of this class automatically ("implicit conversion").
// USAGE with implicit conversion on the call site:
void exampleFunction(Array2DWrapper arr) {
...
arr[i][j];
...
}
// Note how the caller doesn't need to wrap it explicitly:
int * myArrPtr = ...;
exampleFunction(myArrPtr);
If N is not defined globally, you should add it as a member to the class, as well as to the constructor.
class Array2DWrapperDynamicN {
int *ptr;
int N;
public:
Array2DWrapper(int *ptr, int N) : ptr(ptr), N(N) {}
int * operator[](int i) {
return ptr + i*N;
}
};
But now, the implicit conversion doesn't work anymore.
// USAGE:
void exampleFunction(int *arrPtr, int N) {
Array2DWrapperDynamicN arr { arrPtr, N };
...
arr[i][j];
...
}
No.
Operator overloading requires at least one of the argument types to be a class/struct/union. And macros can't do that.
The closest you can get is to pass the array by reference, if possible. E.g.:
template<std::size_t width, std::size_t height>
void doThings(int(& array)[width][height])
{
// access array[i][j];
}
Or if that's not possible, a helper non-operator function, to hide the ugly part:
int& access(int* array, std::size_t i, std::size_t j)
{
return *(arr + i*N + j);
}
Or maybe you need to tackle the underlying problem here. Why is a 2D array passed by int* in the first place?
The important thing to remember here is to not over-complicate things.
One cannot change the behavior of operators for built types. If you want to overload an operator, at least one of the operands must a user-defined type.
Could you explain why I cannot use the const type in a class?
Example code:
class Array {
int *Arr;
int n;
public:
Array(int _n = 0) {
Arr = new int[_n];
n = _n;
}
~Array(void) {
delete []Arr;
}
friend void f(const Array &A) {
A.Arr[0] = 3; // why can the Arr[0], Arr[1] be changed the value ?
A.Arr[1] = 4;
// A.n = 10; // can not be changed because of 'const class type'
}
};
void main()
{
Array A(5);
f(A);
}
When I call f(A), I have defined the const Array &A in f but the elements in void f() are also changeable, but when I try with the code line A.n = 10, it is immutable.
Maybe I should define a const overloading operator or something in order to make all of the elements in Arr immutable.
Question: How can I make elements of Arr immutable?
Maybe i should define a 'const' overloading operator or something in
order to make all of the elements in 'Arr' are immutable.
A.Arr[i] in your case is not immutable. A.Arr is.
You can not do the following:
A.Arr = newaddress;
++A.Arr; // etc
To overcome this problem, get rid of C style pointer (dynamic memory) and use:
int Arr[somesize];
or some container like std::array or std::vector to ensure your array is immutable.
Live demo of compilation failing with std::vector as container.
const Array &A means that the A object is to be treated as constant, so its members can't be modified; but other objects, such as those in the array that A.Arr points to, are not.
n = 10; is impossible not because A is const, but because a friend function is not a member, so there is no n. The const would prevent A.n = 10;
You could prevent modification of the array by only allowing access via member functions, not via the pointer:
public:
Type & operator[](size_t i) {return Arr[i];}
Type const & operator[](size_t i) const {return Arr[i];}
Now A[i] can only be used for modification if A is mutable.
Just to complete the answers, since your class is named Array, you should have overloaded the array subscript operator accordingly:
int &operator[](int index) { return Arr[index]; } // non-const overload
int operator[](int index) const { return Arr[index]; } // const overload
With that, you'll no longer have to mess with that friend function.
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.
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.
I am writing a matrix class in c++ and trying to overload some operator like = and >> and << etc.
I was unable to overload operator [][] for matrix class.
if i have an object of class matrix like M1 then i can use this way for giving value to each element:
M1[1][2]=5;
OR
int X;
X=M1[4][5];
Just overload operator[] and make it return a pointer to the respective row or column of the matrix. Since pointers support subscripting by [], access by the 'double-square' notation [][] is possible then.
You can also overload operator() with two arguments.
There is no operator[][] in C++. You have to return a helper object and then overload operator[] for that too, to have this kind of access.
You could overload operator[]. So if you would like to use matrix that way, you should make matrix as array of vectors.
class Matrix
{
...
Vector & operator[]( int index );
...
};
and
class Vector
{
...
double & operator[]( int index );
...
};
Finally:
Matrix m;
...
double value = m[i][j];
...
there is no operator[][], you can implement operator[] to return a reference to the row/column object, in which you can implement the operator[] to return you the cell reference.
You can do something like the following to avoid all that hassle..
struct loc
{
int x;
int y;
};
then in your operator[] overload, accept a loc, something like
T& operator[](loc const& cLoc)
{
// now you have x/y you can return the object there.
}
To call, you can simply do something like:
matrix[loc(2,3)] = 5;
Actually, I did just that in my own matrix class a few years ago. In this case, I defined a matrix template class that contained the snippet, below.
I was then able to iterate and assign as follows:
for(size_t k=1; k<n; ++k) {
minor[p][k-1]=major[j][k];
}
I hope this helps.
// //////////////////////////////////////////////////////////////////////////////
// list is internal vector representation of n x m matrix
T* list;
// Proxy object used to provide the column operator
template < typename T >
class OperatorBracketHelper
{
Matrix < T > & parent ;
size_t firstIndex ;
public :
OperatorBracketHelper ( Matrix < T > & Parent , size_t FirstIndex ) :
parent ( Parent ), firstIndex ( FirstIndex ) {}
// method called for column operator
T & operator []( size_t SecondIndex )
{
// Call the parent GetElement method which will actually retrieve the element
return parent.GetElement ( firstIndex , SecondIndex );
}
};
// method called for row operator
OperatorBracketHelper < T > operator []( size_t FirstIndex )
{
// Return a proxy object that "knows" to which container it has to ask the element
// and which is the first index (specified in this call)
return OperatorBracketHelper < T >(* this , FirstIndex );
}
T & GetElement ( size_t FirstIndex , size_t SecondIndex )
{
return list[FirstIndex*cols+SecondIndex];
}
I am exactly working on a matrix class and I decided to first create an Array class which has a dynamic 2-D array. So, well just as you, I confronted this obstacle that how I can overload two square brackets. How I approached this case is very simple; I overloaded the square brackets operator twice as member functions. First, I overloaded [] so as to return a pointer pointing to the desired row, so to speak, and then the following member function (i.e. again operator [] overloaded) returns a lvalue of the same type as the array's elements.
However, note that the index you inter to invoke the former overloaded operator [] must be saved somewhere so that you may use it in the latter overloaded operator []. For this reason I simply added a new member of the type int to the class Array (which I've named it "test" in my code below).
class Array {
private:
double **ptr; int test;
... /* the rest of the members includes the number of rows and columns */
public:
Array(int=3,int=3); // Constructor
Array(Array &); // Copy Constructor
~Array(); // Destructor
void get_array();
void show_array();
double* operator[] (int);
double operator[] (short int);
...
};
...
double* Array::operator[] (int a) {
test = a;
double* p = ptr[test];
return p;
}
double Array::operator[] (short int b) {
return ((*this)[test][b]);
}
Therefor, as an example, in main I can simply write:
int main(){
Array example;
cout << example[1][2];
}
I hope this would help you.
You can't overload [][] as such, since there isn't such an
operator. You can overload [] to return something which also
has an [] defined on it (a proxy); in the simplest case,
something like a double* will work, but it's usually better,
although a bit more work, to use a full class. (Place to add
bounds checking, for example.)
Alternatively, you can overload (x,y). Depending on who you
ask, one format or the other is "better". (In fact, it's
strictly a question of style.)
Template matrix class
template <uint8_t rows, uint8_t cols, typename T>
class MatrixMxN {
public:
T* operator[](uint8_t f_row) {
return &m_val[f_row * cols];
}
protected:
T m_val[rows*cols];
};
and here is object of matrix with 3 row, 4 column and integer type.
MatrixMxN<3, 4, int32_t> M;
M[2][3] = 10;
std::cout << M[2][3] << std::endl;