How to Overload Array Index Operator for Wrapper Class of 2D Array

How to overload array index operator for wrapper class of 2D array?

The easier solution is to use the operator() as it allows multiple parameters.

class M
{
public:
int& operator()(int x,int y) {return at(x,y);}
// .. Stuff to hold data and implement at()
};

M a;
a(1,2) = 4;

The easy way is that the first operator[] returns an intermediate object that the second operator[] returns the value from the array.

class M
{
public:
class R
{
private:
friend class M; // Only M can create these objects.
R(M& parent,int row): m_parent(parent),m_row(row) {}
public:
int& operator[](int col) {return m_parent.at(m_row,col);}
private:
M& m_parent;
int m_row;
};

R operator[](int row) {return R(*this,row);}

// .. Stuff to hold data and implement at()
};

M b;
b[1][2] = 3; // This is shorthand for:

R row = b[1];
int& val = row[2];
val = 3;

Operator[][] overload

You can overload operator[] to return an object on which you can use operator[] again to get a result.

class ArrayOfArrays {
public:
ArrayOfArrays() {
_arrayofarrays = new int*[10];
for(int i = 0; i < 10; ++i)
_arrayofarrays[i] = new int[10];
}

class Proxy {
public:
Proxy(int* _array) : _array(_array) { }

int operator[](int index) {
return _array[index];
}
private:
int* _array;
};

Proxy operator[](int index) {
return Proxy(_arrayofarrays[index]);
}

private:
int** _arrayofarrays;
};

Then you can use it like:

ArrayOfArrays aoa;
aoa[3][5];

This is just a simple example, you'd want to add a bunch of bounds checking and stuff, but you get the idea.

How do create an overloaded operator for the form a[x][y]?

Here's a nice base implementation that does exactly what you want.

Update (September 26, 2013): I have improved the code quite a lot.

The type T in the template only needs to satisfy the requirements of an std::vector.

#include <vector>
#include <stdexcept>

template<typename T>
class matrix {
class row {
std::vector<T> values;
public:
row(std::size_t n)
: values(n, T()) {}

T& operator[] (std::size_t index) {
if (index < values.size())
return values[index];
else
throw std::domain_error("Matrix column index out of bounds.");
}
const T& operator[] (std::size_t index) const {
if (index < values.size())
return values[index];
else
throw std::domain_error("Matrix column index out of bounds.");
}

std::size_t size() const { return values.size(); }
};

std::vector<row> rows;

public:
matrix(std::size_t m, std::size_t n)
: rows(m, row(n)) {}

row& operator[](std::size_t index) {
if (index < rows.size())
return rows[index];
else
throw std::domain_error("Matrix row index out of bounds.");
}
const row& operator[](std::size_t index) const {
if (index < rows.size())
return rows[index];
else
throw std::domain_error("Matrix row index out of bounds.");
}

std::size_t row_count() const { return rows.size(); }
std::size_t col_count() const {
if (rows.size()) return rows[0].size();
return 0;
}

std::size_t size() const { return row_count() * col_count(); }
};

For convenience, this helper can be used to print a matrix.

#include <ostream>

template<typename T>
std::ostream& operator <<(std::ostream& o, const matrix<T>& mat) {
for (std::size_t i = 0u; i < mat.row_count(); ++i) {
for (std::size_t j = 0u; j < mat.col_count(); ++j) {
o << mat[i][j] << ' ';
}
o << '\n';
}
return o;
}

And just for you, a usage example to test this:

int main() {
matrix<int> mat_0(2, 3);
matrix<double> mat_1(1, 2);

mat_0[0][0] = 2;
mat_0[0][1] = 3;
mat_0[0][2] = 4;
mat_0[1][0] = 3;
mat_0[1][1] = 7;
mat_0[1][2] = 9;

mat_1[0][0] = 0.43;
mat_1[0][1] = 213.01;

std::cout << mat_0;
std::cout << '\n';
std::cout << mat_1;

return 0;
}

Overload = operator for class that shall behave like matrix

If you intend to modify the element of the matrix referenced by the proxy, then the overload of operator[] in the Proxy class must return a reference:

int& operator[](int index)

At the moment, you return int, which makes a copy of the element’s value—not what you want. There ought to be a const overload as well, so that operator[] works on const matrices. This one can return by value:

int operator[](int index) const

And actually, size_t would be more appropriate for the index than int, since it’s an unsigned type. You aren’t giving any particular meaning to negative indices, so it makes sense to disallow them.

You don’t need to overload operator= of Proxy unless you want to assign a whole row at once. In fact, you don’t need the Proxy class at all, because you can just return a pointer to the row array directly. However, if you want to change your design—e.g., using a sparse or packed representation—then the Proxy would let you keep the m[i][j] interface.

Overloading the [] operator in python class to refer to a numpy.array data member

You need to implement the __getitem__ and __setitem__ magic functions.

A complete overview for the magic methods can be found here.

import numpy as np

class MyArray():
def __init__(self):
self.data = np.zeros(10)

def __getitem__(self, key):
return self.data[key]

def __setitem__(self, key, value):
self.data[key] = value

def __repr__(self):
return 'MyArray({})'.format(self.data)

a = MyArray()

print(a[9])
print(a[1:5])
a[:] = np.arange(10)
print(a)

Which will give you this result:

0.0
[ 0. 0. 0. 0.]
MyArray([ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.])

Inheritance

If you just want to modify or add behaviour of np.ndarray, you could inherit from it. This is a little more complicated than for normal python classes, but implementing your case should be not that hard:

import numpy as np

class MyArray(np.ndarray):

def __new__(cls, shape, fill_value=0, dtype=float):
data = np.full(shape, fill_value, dtype)
obj = np.asarray(data).view(cls)
obj.fill_value = fill_value
return obj

def reset(self, fill_value=None):
if fill_value is not None:
self.fill_value = fill_value

self.fill(self.fill_value)

For more info, see here.

How can I invoke an overloaded () operator on the keyword this?

You have a few options:

  • (*this)(5)

  • this->operator()(5)

  • or just operator()(5)

  • Create a method that you call from within the operator(), e.g.:

    void do_work(int a) { /* ... */ }
    void operator()(int a) { do_work(a); }
    void myFunc() { do_work(5); }

Whichever you choose is just a matter of personal taste.


Just for fun, here are some more (ridiculous) options:

  • std::invoke (mentioned in comments):

    std::invoke(&MyStruct::operator(), this, 5);
  • mem_fn:

    auto call_op = std::mem_fn(&MyStruct::operator());
    call_op(this, 5);
  • lambda:

    auto call_op = [this] (int a) { operator()(a); };
    call_op(5);
  • bind_front

    auto call_op = std::bind_front(&MyStruct::operator(), this);
    call_op(5);

Overloading subscript operator and working with double-pointers?

It's not clear why you are using double indirection in the first place.

If pixels is a double pointer to an array of pixels, you can do

pixels& MyWrapper::operator[] (const int nIndex) {
return (*Image.pixels)[nIndex]; // where Image is of type image
}

If pixels is a pointer to an array of pointers to arrays, then you need two indices:

pixels& MyWrapper::operator() ( int xIndex, int yIndex ) {
return Image.pixels[yIndex][xIndex]; // where Image is of type image
}

There are a few weird things going on here.

  • typedef class { } identifier is not good C++. Use class identifier { };, or else the class has no name, so you cannot define member functions outside the class { } scope. (Among other problems.)
  • There is no reason to make a parameter type const int. Plain int accomplishes the same thing.
  • There is no apparent reason for the double indirection. Typically in C++ we avoid the direct use of pointers. There is probably a prepackaged standard structure you can use instead.

dynamical two dimension array according to input

Boost implements matrices (supporting mathematical operations) in its uBLAS library, and provides usage syntax like the following.

#include <boost/numeric/ublas/matrix.hpp>

int main(int argc, char* argv[])
{
unsigned int N = atoi(argv[1]);
boost::matrix<int> myMatrix(N, N);

for (unsigned i = 0; i < myMatrix.size1 (); ++i)
for (unsigned j = 0; j < myMatrix.size2 (); ++j)
myMatrix(i, j) = 3 * i + j;

return 0;
}


Related Topics



Leave a reply



Submit