C ++ 2D массивы конструктора объектов - PullRequest
1 голос
/ 23 декабря 2008

В моем Dev C ++ я пытаюсь создать класс 2D Array, который действует как Grid. Но одна из проблем заключается в том, что я не уверен, что нужно для конструктора.

Когда я пытаюсь скомпилировать, я получаю следующие ошибки: В конструкторе 'Grid :: Grid (int, int)': 'sqaures' не тип 'yPos' не может появляться в константном выражении [Ошибка сборки] [grid.o] Ошибка 1

Вот заголовочный файл:

#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

И вот .cpp файл для функций 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 
}

Мой конструктор в файлах .cpp не работает, и я не уверен, что делать. У кого-нибудь есть какие-нибудь решения?

Ответы [ 7 ]

4 голосов
/ 23 декабря 2008

Есть несколько проблем с вашим кодом. Прежде всего, ваша переменная-член "squares" должна быть указателем на int , а не int :

int *squares;

Тогда следующая строка выдаст ошибку:

squares = new squares[xPos][yPos];

Что вам действительно нужно, так это блок памяти для двумерного массива:

squares = new squares[xPos * yPos];

Кроме того, вы должны сохранить размеры этого массива в переменных-членах (например, «sizeX» и «sizeY»)

Теперь у вас есть блок памяти, который будет содержать двумерный массив квадратов. Я обычно перегружаю оператор () для доступа к элементу в этом массиве:

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

Если у вас проблемы с оператором, просто создайте функцию-член:

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;
}

Наконец, вам нужен деструктор, чтобы освободить память:

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

Вот как мне нравится это делать (стиль "C-with-classes"). В другом ответе Дэвид Норман дает хороший «стандартный C ++» способ реализации вашего класса.

3 голосов
/ 23 декабря 2008

Не имеет прямого отношения к вашему вопросу, но вы не должны использовать объявления в заголовочных файлах (.h / .hpp).

например:

using namespace std;

Они принадлежат файлам cpp.

См. Херб Саттерс GOTW (Гуру недели) # 53 по причинам.

2 голосов
/ 23 декабря 2008

Чтобы избежать проблем с памятью, используйте вектор векторов.

В шапке

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

В .cpp

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

Позже:

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

Или используйте вектор вектора умных указателей, если вы хотите создать новые квадраты.

1 голос
/ 23 декабря 2008

Согласно ответу Дэвида Нормана , используйте std::vector. Однако в его ответе есть ошибка, вектор должен быть объявлен следующим образом:

class Grid
{
...

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

Вы также можете инициализировать его, используя векторный конструктор, который принимает размер и значение:

Grid::Grid(int xPos, int yPos)
:   squares( xPos, std::vector<int>( yPos, 0 ) )
{
}
1 голос
/ 23 декабря 2008

Это не работает:

squares = new squares[xPos][yPos];

Вам нужно:

squares = new (int*)[xPos];
for (int x = 0; x < xPos; ++x) {
     squares[x] = new int[yPos];
}

И лично это неправильный способ сделать это. Я предпочитаю

class Grid {

     class Row {
         int* row; // this is a pointer into Grid::grid
         int size; // this equals Grid::col_count and is only here for bounds checking
     public:
         Row(int s, int* r) : size(s), row(r) {}

         int& operator[](int col) {
             if (col >=0 && col < size) return row[col];
             throw OutOfBoundsException();
         }
     };

     int row_count, col_count;
     int* grid;
     Row* rows;

  public:
     Grid(int x, int y) : row_count(x), col_count(y) {
         rows = new (Row*)[row_count];
         grid = new int[row_count*col_count];
         int* grid_walk = grid;
         for (int i = 0; i < row_count; ++i) {
             rows[i] = new Row(col_count, grid_walk);
             grid_walk += col_count;
         }
     }
     ~Grid() { delete[] rows; delete[] grid; }

     Row& operator[](int row) {
         if (row ?= 0 && row < row_count) return rows[row];
         throw OutOfBoundsException();
     }

     int rows() const { return row_count; }
     int cols() const { return col_count; }

};

Grid checkers(8,8);

for (r = 0; r < checkers.row_count(); ++r) {
    for (c = 0; c < checkers.col_count(); ++c) {
        if ((r + c) % 2 == 1) checkers[r][c] = -1; // red space
        else if (r < 3) checkers[r][c] = 1; // player 1
        else if (r >= 5) checkers[r][c] = 2; // player 2
        else checkers[r][c] = 0; // open square
    }
}
// etc.

Надеюсь, опечаток не слишком много.

1 голос
/ 23 декабря 2008
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 
}

Это, конечно, неправильно. Вы должны сделать new int[xPos][yPos]. Оператор требует, чтобы вы указали его тип. Но все же тогда вы еще не закончили. yPos должно быть известно во время компиляции. В вашем примере это не так. Причина в том, что он становится частью типа, возвращаемого новым выражением:

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

Поскольку типы являются статическими, yPos не могут быть определены во время выполнения. То, что вы действительно хотите, это вектор int. Но я полагаю, что вы хотите сами управлять памятью, потому что хотите выучить языковые правила. Так что иди с этим:

  1. Сделать квадраты int*: int *squares;
  2. Измените строку в конструкторе на squares = new int[xPos * yPos];
  3. Добавьте строку типа delete[] squares; в свой деструктор.
  4. Добавьте конструктор копирования и оператор копирования, который копирует по вашей памяти, когда копируется ваш экземпляр.
  5. добавить функцию-член, подобную приведенной ниже:

Код:

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

Который даст вам целое число в данной позиции. Конечно, вы также можете перегружать operator[], чтобы иметь естественный доступ, используя 2d индексы:

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); 
    }
};

Внешний индекс выберет строку, внутренний - столбец. Если вам нужно правильно управлять памятью, вы можете перейти к лучшим решениям. Для вашей задачи идеально подходит boost::multi_array: Boost.MultiArray

Другие проблемы

Никогда не делайте using namespace std; в заголовочном файле. Причина в том, что во весь код, который косвенно или напрямую включает этот файл, также будет автоматически включена эта строка, и поэтому он будет видеть весь std :: Конфликты имен произойдут, как только код попытается сослаться на имена, которые также определены в стандартной библиотеке C ++.

1 голос
/ 23 декабря 2008

Вы уверены, что правильно поняли код? Ваши квадраты определяются как int, а не как int **? Я не уверен, как вы получаете это для компиляции ....

EDIT: Сообщение об ошибке, которое вы получаете, когда вы определяете квадраты как целые. Следовательно, он может принимать только одно целое число. Ваш конструктор пытается присвоить ему целый массив. Вы достаточно знакомы с указателями, массивами, разыменованием и всем этим? Двумерный массив, как правило, сложно.

Если вы хорошо напишите свой 2D-массив, вы можете фактически использовать один массив и просто отобразить двумерные адреса в один индекс.

...