[C++]Modelling a 2D-Array of Multiple Types
Published: 2021-07-13 21:06:42

In my previous [article](https://codepadawan.hashnode.dev/modelling-an-array-of-multiple-types-using-templates)(which i recommend you read before this) I modeled a 1-D array that can hold multiple types, today i'm going a step further to model a 2D-Array of multiple types using the same technique i used before which is **templates**.
I want my 2D-Array to have a :
> `.at()` method which takes two numbers(row, column) as input and returns the value at that position.

> `.fill()` method which replaces the values in all rows/column to what the user specified(the value specified is dependent on the type the array is modelling).

> `.swap()` method which swaps the values of two 2D-Arrays.

> `.size()` method which returns the size of the array.

This is what it would look like:
```C++
#include <iostream>
template<typename T, size_t R, size_t C>
class Array_2D{
    T arr[R][C];
    size_t row{R};
    size_t column{C};
    friend std::ostream &operator<<(std::ostream &os, Array_2D<T, R, C> &obb){
        
        for(size_t i{0}; i < obb.row; ++i){
            os << "[ ";
            for(size_t j{0}; j < obb.column; ++j){
                os << obb.at(i,j) << " "; 
            }
            os << "]\n";
        }
        return os;
    }
public:
    Array_2D(){
        T obj;
        fill(obj);
    }
    Array_2D(T obj){
        fill(obj);
    }
    Array_2D(Array_2D &obj){
        for(size_t i{0}; i < obj.row; ++i){
            for(size_t j{0}; j < obj.column; ++j){
                this->at(i,j) = obj.arr[i][j];
            }
        }
    }
    size_t size(){
        return row*column;
    }
    T& at(size_t a, size_t b){
        return arr[a][b];
    }
    void fill(T fil){
        for(size_t i{0}; i < this->row; ++i){
            for(size_t j{0}; j < this->column; ++j){
                arr[i][j] = fil;
            }
        }
    }
    
    void swap(Array_2D &obj){
        Array_2D<T, R, C> temp{obj};
        obj = *this;
        *this = temp;
    }
};
```
> I've overloaded the stream insertion operator to make it easy for me to output my 'user-defined class'(Array_2D).

I create a template which has three template parameter:
> `typename T` represents the type the array will model which the user will specify when creating a Array_2D object.

> `size_t R` and `size_t C` which represents the numbers of rows\column in the array, `size_t` is an unsigned type meaning it can only have values less then zero which is perfect in this case because obviously the rows/column can't be negative. 

I then create the class with 3 data members:

> `T arr[R][C]` which represents the actual 2D-Array of type `T` and row/column `R/C`.

> `size_t row`/ `size_t column` which represents the rows and column for when i need to use the row/column in a class-method/function because i can't use the template parameters for that.

I have a no-args and args constructor, which call the `fill()` method that replaces all the values with the default values of the type the array is modelling(no-args constructor) or what the user specified(args-constructor). I have a `.size()` method that returns the number of items the array can hold and a copy constructor that allows us to give the value of an `Array_2D` object to another easily :

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1618231687156/_9AHllEIp.png)

I have a `.at()` method that expects two numbers of unsigned type, which returns the value by reference(in case it needs to be modified) of the value of the array at the specified indexes(`[a][b]`)

A `.fill()` method which expects an object of type `T` which is the same type of the elements that the array is modelling, it replaces all the values in the array to what the user passed into it.

A `.swap()` method which takes another '2D-Array' of the same type as the one on the left hand of the operator and swaps their values(They have to have the same number of row and column).

TEST CASES:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1618233095970/d9h6qu9G2.png)

### EXTRAS
If i wanted to take things a bit further and give the class the ability to have methods like `.begin()` and `.end()` which return iterators to the beginning and one past the last value in the array, then i would have to give the class the ability to use Iterators by writing an iterator class for my `Array_2D` class, it would look like this:
```C++
#include <iostream>
#include <iterator>
#include <cstddef>
template<typename T, size_t R, size_t C>
class Array_2D{
    T arr[R][C];
    size_t row{R};
    size_t column{C};
    friend std::ostream &operator<<(std::ostream &os, Array_2D<T, R, C> &obb){
        
        for(size_t i{0}; i < obb.row; ++i){
            os << "[ ";
            for(size_t j{0}; j < obb.column; ++j){
                os << obb.at(i,j) << " "; 
            }
            os << "]\n";
        }
        return os;
    }
public:
////ITERATORS
    struct Iterator{
        using iterator_category = std::bidirectional_iterator_tag;
        using difference_type   = std::ptrdiff_t;
        using value_type        = T;
        using pointer           = T*;
        using reference         = T&;
        
        Iterator(pointer ptr) : m_ptr(ptr) {}
        reference operator*() const { return *m_ptr; }
        pointer operator->() { return m_ptr; }

        Iterator& operator++() { 
            m_ptr++;
            return *this;
        }  

        Iterator operator++(int) {
            Iterator tmp = *this;
            ++(*this);
            return tmp; 
        }
        Iterator& operator--(){
            --m_ptr;
            return *this;
        }
        Iterator operator--(int){
            Iterator tmp = *this;
            --(*this);
            return tmp;
        }
        friend bool operator== (const Iterator& a, const Iterator& b) { return a.m_ptr == b.m_ptr; };
        friend bool operator!= (const Iterator& a, const Iterator& b) { return a.m_ptr != b.m_ptr; }; 
private:
    pointer m_ptr;
    };
////
    Iterator begin() { 
        return Iterator(&arr[0][0]);
    }
    Iterator end()   { 
        return Iterator(&arr[row-1][column-1]); 
    }
    Array_2D(){
        T obj;
        fill(obj);
    }
    Array_2D(T obj){
        fill(obj);
    }
    Array_2D(Array_2D &obj){
        for(size_t i{0}; i < obj.row; ++i){
            for(size_t j{0}; j < obj.column; ++j){
                this->at(i,j) = obj.arr[i][j];
            }
        }
    }
    size_t size(){
        return row*column;
    }
    T& at(size_t a, size_t b){ 
        return arr[a][b];
    }
    void fill(T fil){
        for(size_t i{0}; i < this->row; ++i){
            for(size_t j{0}; j < this->column; ++j){
                arr[i][j] = fil;
            }
        }
    }
    
    void swap(Array_2D &obj){
        Array_2D<T, R, C> temp{obj};
        obj = *this;
        *this = temp;
    }
};
```
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1618234601027/WLN9zgjwu.png)

But the `.end()` method that returns an iterator one past the last element isn't behaving properly so i didn't add this iterator part to the main blogpost, this is the first time i'm adding iterators to my class so i haven't figured the ins and outs yet, you can see more on adding iterators to user defined class [here](https://internalpointers.com/post/writing-custom-iterators-modern-cpp), and you can come to the repository where i uploaded this 2D-Array class [here](https://github.com/TruePadawan/2D_Array) in case you want to help me figure this stuff out. Thanks