Динамический n-мерный массив частного класса С++

Я искал ответ на StackOverlow, но не нашел его, поэтому надеюсь, что это не дублирование какого-либо сообщения здесь.

Итак, у меня есть следующая проблема.
допустим, у меня есть следующие 2 класса: Rectangle (который построен из другого класса, но в настоящее время нас это не касается) и Grid< /сильный>. с ними следующие конструкторы:

(Конструктор точек для прямоугольника private topLeft и bottomRight):

Point::Point(int x, int y) {this->x = x; this->y = y;}

(Конструктор прямоугольника и класс)

class Rectangle
{
public:
        Rectangle(int l, int u, int w, int h, int color);
        //int getColor() const;
        //void setColor(int color);
        //bool contains(const Point &p) const;
        //void print() const;
private:
        const Point topLeft, bottomRight;
        int color;
};

Rectangle::Rectangle(int l, int u, int w, int h, int color) :
topLeft(l, u),
bottomRight(l + w, u + h)
{ this->color = color; }

(Конструктор сетки и класс) (Предположим, я не хочу инициализировать значения прямоугольника в сетке, просто выделяю их в памяти)

class Grid
{
public:
    Grid(int tileW, int tileH, int width, int height, int color);
    //~Grid();
    //Rectangle& getRectAt(const Point &p);
    //void print() const;
private:
    int count;  
    Rectangle **recs;
};

Grid::Grid(int tileW, int tileH, int width, int height, int color)
{
    int index, index_c=0;
    recs = new Rectangle *[width];

    for (int index = 0; index < width; index++)
    {
        recs[index] = new Rectangle[index];
    }

}

Итак, как вы понимаете, у меня проблема в конструкторе сетки со следующей ошибкой
(Ошибка 1, ошибка C2512: «Прямоугольник»: нет подходящего конструктора по умолчанию.)
но я просто не могу понять, почему это не сработает, я Было предложено выделить двойной указатель Recs как одномерный массив (массив с длиной Width * Height), но что, если Recs был четырехмерным массивом? Как вы могли бы правильно сгладить его, а затем индексировать вокруг 4-мерного массива, не имея головной боли, вычисляя индекс каждой ячейки в массиве.

другое дело, мы знаем, что если бы это был int**, а не rec**, он работал бы отлично

int **foo;
int height,width;
foo = new int* (height);
for (int index = 0; index<height; ++index)
    foo[index] = new int[width];

поэтому я просто продолжаю скучать по способу создания n-мерных массивов в C++.


person Itay.V    schedule 25.11.2016    source источник
comment
Что касается вашей ошибки: у вас нет ни конструктора по умолчанию в Rectangle, ни конструктора, который принимает целое число в качестве параметра. Кроме того, я предлагаю вместо этого использовать std::vectors.   -  person Marco A.    schedule 25.11.2016


Ответы (3)


Строка recs[index] = new Rectangle[index]; пытается вызвать конструктор Rectangle по умолчанию index раза. Если вы хотите создать несколько объектов одновременно, вы, вероятно, захотите добавить ctor по умолчанию и простой метод установки в свой класс Rectangle.

class Rectangle
{
public:
    Rectangle(int l, int u, int w, int h, int color);
    Rectangle() = default;
    void set(int l, int u, int w, int h, int color);
private:
    const Point topLeft, bottomRight;
    int color;
};

Затем в цикле создания:

for (int index_w = 0; index_w < width; index_w++)
{
    recs[index_w] = new Rectangle[height]; //see note below
    for (int index_h = 0; index_h < height; index_h++)
        recs[index_w][index_h].set(/* some math with width, height and loop variables*/, color);
}

Примечание. Я изменил index на height, потому что вы хотите создать 2D-массив, поэтому общий размер сетки равен высоте * ширине. При создании длины индекса вместо этого вы создадите сетку в форме треугольника (и, более того, первая итерация цикла будет recs[0] = new Rectangle[0] - массив нулевой длины).

Как упоминал пользовательский макрос A, рассмотрите возможность использования std::vector<Rectangle> вместо необработанных указателей (2D-массив будет std::vector<std::vector<Rectangle>>)

Кроме того, рассмотрите возможность изменения вашего дизайна, потому что в настоящее время вы создаете сетку H x W объектов Rectangle, где все точки (кроме первой/последней) дублируются на соседних прямоугольниках (каждая точка — это верхний левый угол одного прямоугольника, верхний правый угол). угол другого, нижний левый...).

Я предлагаю класс Grid, который содержит двумерный массив целых чисел и имеет метод Rectangle getRectangle(int x, int y), который возвращает соответствующий набор из 2 точек. Изменение такого класса Grid было бы намного проще, и вам не пришлось бы перебирать все прямоугольники, только целые числа.

person Xeverous    schedule 25.11.2016

Вы можете использовать placement new : сначала вы резервируете достаточно места для хранения массива объектов, а затем создаете их по отдельности, каждый на своем месте.

В вашем коде это может быть (более или менее):

for (int index = 0; index < width; index++)
{
    // first simple allocation for the array
    recs[index] = (Rectangle *) malloc(sizeof(Rectangle) * height);
    for (int j=0; j<height; j++) {
        // individually build each rectangle in place
        new(&recs[index][j]) Rectangle(index*tileW, j*tileH, tileW, tileH, color); 
    }
}

Это предназначено для того, чтобы делать именно то, что вам нужно: создавать массивы нестандартных конструируемых объектов.

Не связано: поскольку вы используете необработанные указатели и выделенные массивы, не забудьте правильно все освободить. Использование std::vectors может спасти вас от этого...

person Serge Ballesta    schedule 25.11.2016

Вы получаете ошибку C2512, потому что у вас нет конструктора по умолчанию в Rectangle. Единственный конструктор, который у вас есть в Rectangle, является параметризованным, в то время как конструктор по умолчанию требует, чтобы его можно было вызывать без дополнительных аргументов.

Глядя на строку recs[index] = new Rectangle[index];, вы видите, что нет аргументов для 5 параметров, которые принимает конструктор. Чтобы эта строка скомпилировалась, вам нужно создать конструктор по умолчанию либо с новым конструктором с сигнатурой Rectangle(), либо с аргументами по умолчанию для параметров в вашем параметризованном конструкторе, например Rectangle(int l = 0, int u = 0, int w = 0, int h = 0, int color = 0);.

Если вы хотите выделить память, вы должны создать конструктор по умолчанию и использовать std::vector<Rectangle>, который вы инициализируете размером. Затем вы можете позже заменить объекты с помощью конструктора копирования, как показано в этом примере: http://ideone.com/KnUBPQ

Что касается создания n-мерного массива, вы явно ограничили его двумерным массивом с вашими классами Rectangle и Point. Если массив будет n-мерным, ваши точки также должны быть n-мерными:

template<int dimensions>
class Point
{
    std::array<int, dimensions> coords;

    ...
};

or

class Point
{
    std::vector<int> coords;

    ...
};
person heksesang    schedule 25.11.2016