0

I'm trying to create a tile system which creates a single instance of a tile, and adds the tile to an array of tiles, allowing you to call Tile::s_tileList[1] to get the dirt tile.

However, I'm having some issues with it. Here's the complete tile code:

tile.h

#pragma once

class Tile {
public:
    static const Tile s_tileList[128]

    static const Tile s_dirt;

    Tile(int tileId);
    virtual ~Tile();
protected:
private:
    int m_tileId;
};

tile.cpp

#include "tile.h"

#include "tile_dirt.h"

const Tile Tile::s_dirt = TileDirt(1); // This line errors

Tile::Tile(int tileId) {
    s_tileList[tileId] = *this;
    m_tileId = tileId;
}

Tile::~Tile() {

}

tile_dirt.h

#pragma once

#include "tile.h"

class TileDirt : Tile {
public:
    TileDirt(int tileId);
    virtual ~TileDirt();
protected:
private:
};

When I'm trying to assign s_dirt to TileDirt I get the following error:

conversion to inaccessible base class "Tile" is not allowed

What am I doing wrong here?

I tried doing:

static const Tile* s_dirt;

And assign it like:

const Tile* Tile::s_dirt = new TileDirt(1);

But that just adds another error: no suitable constructor exists to convert from "const Tile *" to "Tile"

Holt
  • 36,600
  • 7
  • 92
  • 139
Snakybo
  • 429
  • 2
  • 6
  • 17

2 Answers2

3

In C++, a variable of type Foo represents a block of memory sufficient to fit a Foo object in it (basically exactly). And it is exactly data of type Foo.

If you try to fit something else in that memory, you'll get anything from object slicing to undefined behavior (which is bad).

In many other languages (Java, C# to name two), a variable of type Foo actually represents a handle to Foo data elsewhere, or possibly a derived class of Foo. Often these are garbage collected, a non-deterministic system whereby your objects are only destroyed at some unknown point in the future after the runtime engine determines they are nominally unreachable from user code.

To emulate this in C++, you'll want a smart pointer -- std::unique_ptr<Foo> or std::shared_ptr<Foo>. These are not full on garbage collecting smart pointers, but unless you are making self-referential data, they are often good enough. One thing you have to think about in C++ is "who owns the lifetime of this data".

std::shared_ptr is often the easiest to go with.

Replace your Tile instances with std::shared_ptr<Tile>, and your call to new Tile(blah) with std::make_shared<Tile>(blah).

Next, class inheritance by default in C++ is private -- nobody is allowed to know you are a child of your parent class other than instances of your own type. If you want public inheritance, use public Tile.

Your wish to have your Tile constructor store copies of itself in a static array is a bad one. Don't do that kind of thing in the constructor, have it done outside of the constructor. (Producing a shared pointer to this is a bit annoying: the easiest method actually doesn't work well)

Community
  • 1
  • 1
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Thanks for all the info, what exactly do I have to `#include` for `std::shared_ptr`? `iostream` errors with `namespace "std" has no member "shared_ptr"`. – Snakybo Jul 16 '14 at 18:59
  • 1
    @snakybo `#include ` -- you can usually find things like that by googling `std shared_ptr` and looking at the resulting pages, which will include the header file they are defined in. – Yakk - Adam Nevraumont Jul 16 '14 at 19:04
0

The error doesn't match the title of your question.

const Tile Tile::s_dirt = TileDirt(1); // This line errors

You are declaring a global constant (not macro constant, but memory allocated constant, similar to a global variable).

What about doing a test at "main" function, dropping the global stuff, and, the constant stuff, first:

int main(...)
{
  Tile* MyTyle = new TileDirt();
}

And, later, if really required, change to a global member, and, a constant member ?

umlcat
  • 4,091
  • 3
  • 19
  • 29