2

I've been looking all around StackOverlow for an answer but i didn't find one so i hope it isn't duplication of any post around here.

so, i have the next problem.
lets say i have the next 2 classes: Rectangle (Which is built from another class but it doesn't concern us currently) and Grid. with they following constructors:

(Point Constructor for Rectangle private topLeft and bottomRight):

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

(Rectangle Constructor and Class)

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

(Grid Constructor and Class) (Lets assume I don't want to initialize the values of Rectangle in Grid just allocate them in memory)

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

}

so, as you can understand i have problem in Grid constructor with the following Error
(Error 1 error C2512: 'Rectangle' : no appropriate default constructor available.)
but i just cant understand why it wont work, I've been suggested to allocate the Recs double pointer as 1 dimensional array (Array with the length of Width*Height) but what if Recs was 4 dimensional array ? How could you flat it properly and then index around the 4-dimensional array without having a headache calculating the index of each cell in the array.

another thing, we know that if it was int** and not recs** it would work perfectly

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

so i just keep missing the way of doing n-dimensional arrays in C++.

Peter Badida
  • 11,310
  • 10
  • 44
  • 90
Itay.V
  • 169
  • 1
  • 7
  • Regarding your error: you have no default constructor in `Rectangle` nor any that takes an integer as parameter. Plus I kinda suggest using `std::vector`s instead. – Marco A. Nov 25 '16 at 10:05

3 Answers3

1

The line recs[index] = new Rectangle[index]; tries to call Rectangle's default constructor index times. If you want to create multiple objects at once, you probably want to add default ctor and simple setter method to your Rectangle class

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

Then, in creation loop:

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

Note: I have changed index to height, because you want to create 2D array, so the total grid size is height * width. With index length in creation, you would create triangle-shaped grid instead (and more over, the first loop iteration would be recs[0] = new Rectangle[0] - a zero-length array).

As user Macro A mentioned, consider using std::vector<Rectangle> instead of raw pointers (2D array would be std::vector<std::vector<Rectangle>>)

Also, consider changing your design, because currently you are creating a grid H x W of Rectangle objects, where all points (except first/last) are duplicated across adjacent rectangles (each point is upper-left corner of one rectangle, upper-right corner of another, bottom-left...).

I propose a Grid class that holds 2D array of ints and has a method Rectangle getRectangle(int x, int y) which would return appropriate set of 2 points. Modyfying such Grid class would be much easier, and you wouldn't have to iterate over all Rectangles, just ints

Xeverous
  • 973
  • 1
  • 12
  • 25
0

You could use a placement new : you initially reserve enough place to store the array of objects, then individually construct them each in its own place.

In your code, it could become (more or less):

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

This is intended to do exactly what you need : build arrays of non default constructible objects.

Unrelated: as you use raw pointers and allocated arrays, do not forget to correctly free everything. Using std::vectors could save you from that...

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
0

You get error C2512 because you don't have a default constructor in Rectangle. The only constructor you have in Rectangle is parameterized, while a default constructor has the requirement that it must be callable without additional arguments provided.

Looking at the line recs[index] = new Rectangle[index];, you see there are no arguments for the 5 parameters the constructor accepts. For that line to compile, you need to create a default constructor either with a new constructor with the signature Rectangle() or default arguments for the parameters in your parameterized constructor, for example Rectangle(int l = 0, int u = 0, int w = 0, int h = 0, int color = 0);.

If you want to allocate the memory, you should create the default constructor and use std::vector<Rectangle> which you initialize with a size. Then you can later replace the objects by use of a copy-constructor, as shown in this example: http://ideone.com/KnUBPQ

As for creating an n-dimensional array, you've explicitly limited it to a two-dimensional array with your Rectangle and Point classes. If the array is going to be n-dimensional, your points need to be n-dimensional too:

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

    ...
};

or

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

    ...
};
heksesang
  • 171
  • 6