Skip to main content
1 of 3
Loki Astari
  • 97.7k
  • 5
  • 126
  • 341

###Interface:

Even though you are implementing the 2D array as a large 1D array. The user of the array is still expecting to be able to index into the array using the normal array notation.

 Matrix  m(2,3);   // 2D array size 2,3 (default constructed).

 m[1][2] = 4;

You do not want to move the calculation of the position outside the container. If you do this you are exposing implementation details of how the container is built and requiring the user to understand things about the layout of your container. This binds your hands for future modifications and thus breaks encapsulation.

It is technically possible to use the [] to do this. But it is not obvious for beginners (as operator[] can only take 1 parameter) and thus we will use () to simulate the 2D accesses (as this makes the code easier to write).

// The usage of the code will look like this.
// It is not a massive change and people will understand it easily.
// Also the user of the array does not need to know how it is layed out.
m(1,2) = 4;

So your first pass of the interface should look like this:

template <class myType>
class SimpleContainer
{
       std::vector<myType>  data;
       std::size_t          xSize;
       std::size_t          ySize;
    public:
    SimpleContainer(std::size_t xs, std::size_t ys, myType const& defaultValue = myType())
        : data(xs * ys, defaultValue)
        , xSize(xs)
        , ySize(ys)
    {}

    myType&       operator()(std::size_t x, std::size_t y)       {return data[y*xSize + x];}
    myType const& operator()(std::size_t x, std::size_t y) const {return data[y*xSize + x];}
};

Notice I have written two versions of operator(). Both return references to the internal members but one version returns a const reference and is also marked as const.

The normal version:

 myType&       operator()(std::size_t x, std::size_t y)

Allows read/write access to the elements in the array. Because it returns a reference any mutations I do to this object will be reflected in the container copy.

m(4,5) = 6; // Will modify the container version to be 6

The const version:

myType const& operator()(std::size_t x, std::size_t y) const

Allows read only access to the object. This is useful as it allows you to pass your container as a const reference to functions and still access the data. And the compiler will guarantee that the access to the data does not modify it.

If you want to add the ability to do m[1][2] to your container then read this article: http://stackoverflow.com/questions/3755111/how-do-i-define-a-double-brackets-double-iterator-operator-similar-to-vector-of/3755221#3755221

Loki Astari
  • 97.7k
  • 5
  • 126
  • 341