-1

I am trying to create a 2d array pointer with my own class, Tile, as type. I have looked at the code example at How do I declare a 2d array in C++ using new?. The following code works perfectly:

int** ary = new int*[sizeX];
for(int i = 0; i < sizeX; ++i)
    ary[i] = new int[sizeY];

for(int i = 0; i < 8; i++)
    for(int j = 0; j < 8; j++)
        ary[i][j] = 5;

for(int i = 0; i < 8; i++)
    for(int j = 0; j < 8; j++)
        cout << ary[i][j];

However when I try to change type from int to my own class, Tile, I get an

No viable overloaded '='

error in XCode, and I can't figure out what this means. I use the following code:

Tile** t;
t = new Tile*[8];
for(int i = 0; i < 8; ++i)
    t[i] = new Tile[8];

for(int i = 0; i < 8; i++) {
    for(int j = 0; j < 8; j++) {
        t[i][j] = new Tile(new NoPiece());
    }
}

for(int i = 0; i < 8; i++) {
    for(int j = 0; j < 8; j++) {
        cout << (t[i][j].get_piece()).to_string();
    }
}

Here is the code for Tile.cpp:

#include "Tile.h"

Tile::Tile() {

}

Tile::Tile(Piece p) {
    piece = &p;
}

Piece Tile::get_piece() {
    return *piece;
}

And the code for Tile.h:

#include <iostream>
#include "Piece.h"

class Tile {
    Piece * piece;
public:
    Tile();
    Tile(Piece p);
    Piece get_piece();
};
Community
  • 1
  • 1
Robin
  • 1,927
  • 3
  • 18
  • 27

1 Answers1

1

The difference between two code snippets is that the one using int treats array elements like values, i.e. assigns

ary[i][j] = 5;

while the one using Tile treats array elements like pointers:

t[i][j] = new Tile(new NoPiece()); // new makes a pointer to Tile

Change the assignment to one without new to fix the problem:

t[i][j] = Tile(new NoPiece());

There is nothing wrong to making a 2D array of pointers, too - all you need is to declare it as a "triple pointer", and add an extra level of indirection:

Tile*** t;
t = new Tile**[8];
for(int i = 0; i < 8; ++i)
    t[i] = new Tile*[8];

for(int i = 0; i < 8; i++) {
    for(int j = 0; j < 8; j++) {
        t[i][j] = new Tile(new NoPiece());
    }
}

for(int i = 0; i < 8; i++) {
    for(int j = 0; j < 8; j++) {
        cout << (t[i][j]->get_piece()).to_string();
    }
}
// Don't forget to free the tiles and the array
for(int i = 0; i < 8; i++) {
    for(int j = 0; j < 8; j++) {
        delete t[i][j];
    }
    delete[] t[i];
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Thanks for helping me out. NoPiece extends the abstract class Piece, so I changed t[i][j] = new Tile(new NoPiece()); to t[i][j] = new Tile(*new NoPiece());. Do you happen to know what I should do to the line (t[i][j]->get_piece()).to_string(); to call the to_string method in NoPiece, when get_piece() is returning the super class Piece? – Robin May 27 '14 at 11:28
  • 1
    `Tile(*new NoPiece())` leaks memory . How about just taking pieces by value instead of `new`ing everything? This isn't java. – M.M May 27 '14 at 11:35
  • 1
    @Robin To call `to_string` on the base class pointer put `to_string` in the base class of `NoPiece`, and mark it `virtual`. As far as making `*new NoPiece()` change, it's nearly always wrong to dereference with an asterisk a `new`-ed pointer right away, because it leaks memory. If you need a pointer to `Piece` inside `Tile`, change the constructor to `Tile::Tile(Piece *p) {piece = p;}` – Sergey Kalinichenko May 27 '14 at 11:36