2D Array Class constructor and operator[]

so to use in a bigger program I have to write a two dimensional array class, using a provided 1d array class (inheritance). I'm really stumped on writing the normal constructor and the operator[] method. Here is the 1D array class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  class MyArray
{
protected:
    int *_a;     
    int _n;      
public:
    MyArray();                         
    MyArray( int num );                
    MyArray( const MyArray &m );       
    ~MyArray();                        
    int &At( int pos );                
    int &operator []( int pos );       
    int size( void ) const;            
    MyArray &operator =( const MyArray &rhs ); 
};

#include <iostream>
#include "MyArray.h"    
MyArray::MyArray()
{
    int i;
    _a = new int[10];    
    _n = 10;
    for( i = 0; i < 10; i++ )
    {
        _a[i] = 0;     
    }
}
MyArray::MyArray( int num )
{
    int i;
    if( num <= 0 )
    {
        num = 10;
    }
    _a = new int[num];
    _n = num;
    for( i = 0; i < num; i++ )
    {
        _a[i] = 0;       
    }    
}
MyArray::MyArray( const MyArray &m )
{
   *this = m;
}
MyArray::~MyArray()
{
    delete[] _a;
}
int &MyArray::At( int pos )
{
    if( pos < 0 || pos >= _n )
    {
        cout << "Illegal index, pos = " << pos << endl;
        exit( -1 );
    }
    return _a[pos];
}
int & MyArray::operator []( int pos )
{
    if( pos < 0 || pos >= _n )
    {
        cout << "Illegal index, pos = " << pos << endl;
        exit( -1 );
    }
    return _a[pos];
}
int MyArray::size( void ) const 
{
    return _n;
}
MyArray &MyArray::operator =( const MyArray &rhs )
{
    int i;
    if( &rhs == this )
    {
        return *this;  
    }
    if( rhs._n != _n )   
    {
        delete[] _a;    
        _a = new int[rhs._n];
        _n = rhs._n;
    }
    for( i = 0; i < rhs._n; i++ )  
    {
        _a[i] = rhs._a[i];
    }
    return *this;     
}

I know operator[] is supposed to return a &MyArray but I've been trying to solve this problem for hours and I'm stumped.
Last edited on
int & MyArray::operator []( int pos )
this is returning a reference to an int.
MyArray& MyArray::operator []( int pos ) returns a reference to a MyArray object.

Aceix.
The overload you have for operator[] is appropriate for the 1D array class given. It's supposed to return a reference to an array element, and those are of type int.

When you overload operator[] for the 2D array class I suggest you make it return a pointer to integer:
int* My2Darray::operator[](int row)
because that will make using 2 []'s work. The second [] dereferences the pointer returned by operator[].
 
A[1][3] = 7;// assign a value to an array element 
Last edited on
Have a class which represents a row of the two-d array do the bounds-checking, perhaps?
Something along these lines:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <memory>

struct my_array_2d
{
    my_array_2d( std::size_t rows, std::size_t cols, int value = 0 )
        : rows(rows), cols(cols), data( new int[rows*cols] )
    { std::uninitialized_fill( data.get(), data.get() + rows*cols, value ) ; }

    class row
    {
        row( int* begin, std::size_t n ) : row_data(begin), sz(n) {}
        int* row_data ;
        const std::size_t sz ;
        friend struct my_array_2d ;

        public:
            int& operator[] ( std::size_t pos )
            {
                if( pos >= sz ) throw std::out_of_range( "array bounds exceeded" ) ;
                return row_data[pos] ;
            }
    };

    row operator[] ( std::size_t pos )
    {
        if( pos >= rows ) throw std::out_of_range( "array bounds exceeded" ) ;
        return row( data.get() + pos * cols, cols ) ;
    }

    // TODO: const overloads

    const std::size_t rows ;
    const std::size_t cols ;

    private: std::unique_ptr< int[] > data ;
};

int main()
{
    my_array_2d a( 5, 4, 99 ) ;

    for( std::size_t i = 0 ; i < a.rows ; ++i )
    {
        for( std::size_t j = 0 ; j < a.cols ; ++j ) std::cout << a[i][j] << ' ' ;
        std::cout << '\n' ;
    }
    std::cout << '\n' ;

    {
        int n = 10 ;
        for( std::size_t i = 0 ; i < a.rows ; ++i )
            for( std::size_t j = 0 ; j < a.cols ; ++j ) a[i][j] = n++ ;
    }

    for( std::size_t i = 0 ; i < a.rows ; ++i )
    {
        for( std::size_t j = 0 ; j < a.cols ; ++j ) std::cout << a[i][j] << ' ' ;
        std::cout << '\n' ;
    }
}

http://coliru.stacked-crooked.com/a/586eeb5620010237
Thanks JLBorges. That's an ingenious alternative.

I've always felt comfortable with overloading operator[] to go boom, because that's what std::vector would do. We might want some exception safe at() functions though.

Since motez23's assignment has the 2d array derived from a base 1d array object, I thought I'd try building functionality similar to your row object into the 1D array class.

Would you mind giving this a quick sanity check?
In how many ways is this an abomination ?

I added this ctor in the arr1D class for the purpose of supporting operator[] in the derived array2D class.
arr1D( int* pRow, int cols ): pArr(pRow), sz(cols), valid(false) {}
This creates a "dummy" arr1D object with pArr offset to the 1st element of row.
A new bool valid; data member is used because pArr != NULL is no longer a sufficient condition for calling delete [] in ~arr1D().
Now virtual ~arr1D(){ if( valid ) delete [] pArr; }
I also adapted operator= and the copy ctor accordingly.

In the arr1D class I have:
1
2
3
4
5
int& operator[]( int index )
    {
        if( index >= sz ) throw std::out_of_range( "array bounds exceeded" ) ;
        return pArr[index];
    }


In the arr2D class I then have:
1
2
3
4
5
arr1D operator[]( int row )
    {
        if( row >= rows ) throw std::out_of_range( "array bounds exceeded" ) ;
        return arr1D(pArr + row*cols, cols);// similar to your row abject
    }

It does all work, but are there problems with it?
One (specific) question. I wanted the new arr1D ctor to be protected in the arr1D class (do not want user of arr1D creating "dummy" objects), but it wouldn't work (error: arr1D(int*,int) protected in this context. Applies to line 4 in 2nd snippet).

I can use inherited protected data members in arr2D member functions, but not inherited protected functions? Guess I better review the basics.
Last edited on
> It does all work, but are there problems with it?

I think the basic idea behind inheriting arr2d from arr1d is to allow us to treat arr2d object (rows,cols) as an arr1d object (rows*cols). There are no fundamental problems with building functionality similar to the row object into the 1D array class, except a conceptual one of the base class being modified, and being made more complex, to cater to the requirements of a particular derived class.


> I can use inherited protected data members in arr2D member functions, but not inherited protected functions?

A protected member of a base class (of any kind) can only be accessed by member functions and friend functions of a derived class only when operating on an object of a type that is derived from the base class.
http://en.cppreference.com/w/cpp/language/access
Thank you. Got it.

That's the reason for line 15 in your code. It permits the call to the private ctor on line 28.

EDIT: I agree with your concept based objection. An arr1D object should just be what it needs to be.
The row object belongs in the arr2D class, where its functionality is required.
Last edited on
Topic archived. No new replies allowed.