C++ 2D Arrays of an Object Constructor

17,139

Solution 1

There are a few problems with your code. First of all, your member variable "squares" should be a pointer to an int, not an int:

int *squares;

Then, the following line will give an error:

squares = new squares[xPos][yPos];

What you really need is a block of memory for the 2D array:

squares = new squares[xPos * yPos];

Also, you should save the dimensions of this array in member variables (e.g., "sizeX" and "sizeY" )

Now, you have a block of memory which will hold a 2D array of squares. I usually overload the () operator for accessing an element in this array:

int &Grid::operator() (int x, int y)
{
      // you can check array boundaries here
      return squares[y + sizeX*x];
}

If you have problems with the operator stuff, just create a member function instead:

int Grid::get(int x, int y)
{
     // check array bounds
     return squares[y + sizeX*x];
}
void Grid::set(int x, int y, int value)
{
     // check array bounds
     squares[y + sizeX*x] = value;
}

Finally, you need a destructor to free the memory:

Grid::~Grid()
{
     delete [] squares;
}

This is how I like to do it (the "C-with-classes" style). In another answer, David Norman gives a good "Standard C++" way of implementing your class.

Solution 2

Not directly related to your question, but you should not have using declarations in your header (.h/.hpp) files.

e.g.:

using namespace std;

These belong in cpp files.

See Herb Sutters GOTW (Guru of the Week) #53 for reasons.

Solution 3

To avoid lots of memory issues, use a vector of vectors.

In the header

class Grid
{
    ...
    std::vector< std::vector<squares> > squares;
    ...
}

In the .cpp

Grid::Grid(int xPos, int yPos)
{
    squares.resize(xPos);
    for (int i = 0; i < xPos; i++) {
        squares[i].resize(yPos);
    }
}

Later on:

squares[2][3] = square(...);

Or use a vector of vector of smart pointers if you want to new the squares.

Solution 4

As per David Norman's answer, use std::vector. However there is a bug in his answer, the vector should be declared as follows:

class Grid
{
...

    std::vector< std::vector<int> > squares;
};

You can also initialise it using the vector constructor that takes a size and value:

Grid::Grid(int xPos, int yPos)
:   squares( xPos, std::vector<int>( yPos, 0 ) )
{
}

Solution 5

Grid::Grid(int xPos, int yPos) {
    squares = new squares[xPos][yPos];
    //Trying to make squares into a 2D array, and turn the values into the arguments
    //into the the x,y coordinates 
}

That's of course wrong. you have to do new int[xPos][yPos] . The operator requires you to give it a type. But still then, you are not finished. yPos must be known at compile time. In your example it isn't. The reason is because it becomes part of the type that is returned by the new expression:

int (*squares)[yPos] = new int[xPos][yPos];

As types are static, yPos can't be determined at runtime. What you really want is a vector of int. But i figure you want to do the memory management yourself, because you want to learn the language rules. So go with this:

  1. Make squares a int*: int *squares;
  2. Change the line in the constructor into squares = new int[xPos * yPos];
  3. Add a line like delete[] squares; into your destructor.
  4. Add a copy constructor and copy assigment operator that copies along your memory when your instance is copied.
  5. add a member-function like the below:

Code:

int & get(int x, int y) { return squares[y * yPos + x]; }

Which will give you the integer at the given position. Of course, you can also overload operator[] to have natural access using 2d indices:

class Grid {
    struct proxy {
        proxy(int *row):row(row) { }
        int & operator[](int x) {
            return row[x];
        }
        int * row;
    };

    int * squares;
public:
    proxy operator[](int y) {
        return proxy(squares + yPos * y); 
    }
};

The outer index will select the row, the inner will select the column. If you got to manage the memory right, you can change to better solutions. For your task, boost::multi_array is ideal: Boost.MultiArray

Other problems

Never do using namespace std; in a header file. The reason is that all code that indirectly or directly include that file will automatically also have that line included and thus see all of std::. Name conflicts will happen as soon as code tries to reference names that also happen to be defined by the C++ Standard Library.

Share:
17,139
jmucchiello
Author by

jmucchiello

Updated on July 14, 2022

Comments

  • jmucchiello
    jmucchiello almost 2 years

    In my Dev C++, I am trying to create a 2D Array class that acts like a Grid. But one of the problem is I am unsure what do for the constructor.

    When I try to compile, I get the following errors: In constructor 'Grid::Grid(int,int)': 'sqaures' is not a type 'yPos' cannot appear in a constant-expression [Build Error] [grid.o] Error 1

    Here is the Header File:

    #ifndef GRID_H
    #define GRID_H
    
    using namespace std;
    
    class Grid
    {
          public:
    
          Grid(int xPos, int yPos);
          // Constructor
          // POST: Creates the squares of grid; (x,y) coordinates
    
          private:
    
          int squares;
          //2D Array
          //the squares; (x,y) coordinates of the grids      
    };
    
    #endif
    

    And heres the .cpp file for the functions of grid.h

    #include <iostream>
    #include "grid.h"
    
    using namespace std;
    
    Grid::Grid(int xPos, int yPos)
    {
        squares = new squares[xPos][yPos];
        //Trying to make squares into a 2D array, and turn the values into the arguments
        //into the the x,y coordinates 
    }
    

    My constructor in the .cpp files doesn't work and I'm unsure what to do. Does anyone have any solutions?

  • codelogic
    codelogic over 15 years
    He isn't according to his question.
  • Uri
    Uri over 15 years
    I misunderstood his compiler message. I think that he forgot a period somewhere in it.