Reputation: 77
I am making a Pentago game for someone, and I wanted to write a good code, so I decided to use operator overloading.
We have 2 classes; first one is Block class (which represents every single block of the board) and the second one is Set class (which represents a 3*3 table of blocks). Now I want to use Set as a 2d array so I can use set[foo][foo]. Can you help me to make an operator like this?
Upvotes: 4
Views: 335
Reputation: 8220
Assuming the memory is contiguous, you can return a pointer to the first element of the row.
#include <iostream>
class MyType
{
public:
static const size_t rows = 3;
static const size_t columns = 3;
static const size_t size = rows * columns;
MyType()
{
for(size_t index = 0; index < 9; ++index)
{
data[index] = index;
}
}
int* operator[](size_t index)
{
return &data[rows * index];
}
private:
int data[size];
};
int main()
{
MyType instance;
std::cout << instance[2][1] << std::endl;
}
Upvotes: 0
Reputation: 76297
There are (at least) two ways to go here.
The first is to make something like a set_row
class, which is a proxy. So you'd have something like
class set
{
public:
set_row operator[](size_t row)
{
// Return a proxy object that just sees the correct row.
return set_row(internal_buffer_pointer[row]);
}
...
};
where set_row
is something like
class set_row
{
public:
// Ctor takes a row
// Take a column, and return a reference to the correct column in the row.
element &operator[](size_t column);
};
From experience (on, ahem, VisualC++), this was slow, as it will need to construct a proxy object for each access.
The second is to forgo operator[]
, and use operator()
:
class set
{
public:
element &operator()(size_t row, size_t col);
...
};
It would be nice using operator[]
, but, unfortunately, you can't do that with it.
Upvotes: 3
Reputation: 48615
There is no operator[][]
. If you want to provide those semantics you need to overload operator[]
such that it returns another object that also overloads operator[]
.
Your case can be solved using a vector of vectors:
#include <vector>
#include <cstdint>
#include <iostream>
struct Block
{
int value = 0;
};
class Set
{
std::vector<std::vector<Block> > grid;
public:
Set(): grid(3, std::vector<Block>(3)) {} // 3 x 3
std::vector<Block>& operator[](std::size_t x) { return grid[x]; }
};
int main()
{
using std::size_t;
Set set;
set[1][1].value = 1;
for(size_t x = 0; x < 3; ++x)
{
for(size_t y = 0; y < 3; ++y)
{
std::cout << set[x][y].value << ' ';
}
std::cout << '\n';
}
}
Output:
0 0 0
0 1 0
0 0 0
This works because Set::operator[]
returns reference to a std::vector
and the std::vector
overloads operator[]
to return a reference to a Block
.
Upvotes: 1
Reputation: 114481
A very simple solution is
struct MyClass {
int x[3][3];
int* operator[](int row) { return &(x[row][0]); }
};
i.e. returning an element*
from operator[]
.
This allows using
myinstance[row][col]
Upvotes: 3
Reputation: 36597
There is no way to supply an operator[][]
for a class.
However, if your Set
supplies an operator[]()
, that operator can return a reference to something else that also has an operator[]()
.
For example;
class Row
{
public:
Block &operator[](int block_no) {return data[block_no];};
private:
std::vector<Block> data;
};
class Set
{
public:
Row &operator[](int row_no) {return row[row_no];};
private:
std::vector<Row> row;
};
int main()
{
Set s;
// assume s is set up appropriately
Block b = s[2][3]; // equivalent to s.operator[](2).operator[](3)
}
Obviously, it is also necessary to do relevant error checking, set up the contents of the classes correctly, etc.
Upvotes: 1