I've got a bit of a problem here. I'm trying to define several classes, of which some are Players and some are Pawns belonging to the players. Coming from Python, I'm used to being able to conveniently access a Pawn's owning Player through the Pawn, as well as accessing a Player's Pawns through the Player. Correct me if I'm wrong, but this seems impossible in C++.
I currently define Player first, and one of its data members m_Pawns is supposed to be a vector<Pawn>. I declare the data member, but I don't assign it any value. I also define a member function that is meant to assign a vector of pawns to m_Pawns, but I don't call it anywhere near the constructor. Since I'm not actually calling the constructor for Pawn in the constructor for Player, it seems I should be fine.
Here's my Player class. The Board class is defined beforehand, whereas the Pawn class is defined afterwards (the Pawn class contains pointers to an owner of the Player class, so switching it around doesn't really help).
class Player
{
public:
Player(sf::Color color, const string& name);
sf::Color GetColor();
string GetName();
void CreatePawns(Board& board, int which);
protected:
vector<Pawn> m_Pawns;
sf::Color m_Color;
string m_Name;
};
Player::Player(sf::Color color, const string& name):
m_Color(color),
m_Name(name)
{}
sf::Color Player::GetColor()
{
return m_Color;
}
string Player::GetName()
{
return m_Name;
}
void Player::CreatePawns(Board& board, int which)
{
switch(which)
{
case 1:
for(int i = 0; i < 4; ++i)
{
m_Pawns.push_back(Pawn((*board).Cluster1[i], this*, m_Color));
}
break;
case 2:
for(int i = 0; i < 4; ++i)
{
m_Pawns.push_back(Pawn((*board).Cluster2[i], this*, m_Color));
}
break;
case 3:
for(int i = 0; i < 4; ++i)
{
m_Pawns.push_back(Pawn((*board).Cluster3[i], this*, m_Color));
}
break;
default:
cout << "Invalid player ID!\n\n";
break;
}
}
If the class Player is coming first and class Pawn coming later then you can only declare pointer or reference to the later class (here Pawn). You cannot have objects of later class, e.g.
class Player {
Pawn* p; // allowed
Pawn& r; // allowed
vector<Pawn*> p; // allowed
vector<Pawn&> vr; // not allowed (reference are not copyable)
vector<Pawn> o; // error !
};
class Pawn {};
There is no way you can overcome this situation, as in C++ for non-template class one need to show full definition to declare objects.
The only way out is to reformat your code or use pointer/reference (with forward declaration).
The class Pawn still has to be defined so compiled can instantiate vector. You can get away with storing references or pointers to Pawn objects in your vector instead of values; vector for example. In that case forward declaration of class Pawn will be enough.
You can switch it around, because you can forward declare Player, and then Pawn can have a pointer to it.
You can take a pointer to an incomplete type. You can't hold values of that type.
You can do something like this:
class Pawn;
class Player {
}
class Pawn {
}
Related
I have two classes Instructor and Game.
Instructor.h
class Instructor
{
int instrID;
public:
Instructor();
void showGameStatus();
int createGame();
vector<int> createGames(int numberOfGames);
};
Game.h:
class Game {
private:
int gID;
int instrID;
int pFactID;
public:
Game() { // default constructor
gID = 0;
instrID = 0;
pFactID = 0;
};
These are in Instructor.cpp
void Instructor::showGameStatus()
{
}
int Instructor::createGame()
{
Game g;
}
CreateGame() initializes a game. I want that upon calling showGameStatus() I can print out all properties (eg gId, InstrId) of the Game g that initialized earlier etc.
Is it possible to access the properties of Game g that in another method?
This should do it. Class Instructor should inherit class Game:
class Instructor::public Game{
your code here
}
The short answer is: No.
The longer answer is this: If I understand correctly, what you want to accomplish, the problem is that the object g of type Game is held by a local variable inside the scope of your Instructor::createGame member function. Once that function is "done", i.e. the local scope ends, the object, which has automatic storage will be destroyed. It's gone. I don't know what the int means that you return, but no matter what it does, it doesn't hold an object of type Game.
Now, you probably want your createGame to return some type of handle to an actual Game object. Depending on your specific setting, it is your job to choose how to pass such an object around. For example, one way might be this:
Game Instructor::createGame() const { // 1
Game g;
// do stuff with g, perhaps?
return g;
}
Another might be:
std::unique_ptr<Game> Instructor::createGame() const { // 2
auto gptr = std::make_unique<Game>();
// do stuff with gptr, perhaps?
return gptr;
}
Or yet another:
std::size_t Instructor::createGame() { // 3
// Instructor has a member std::vector<Game> games
games.emplace_back();
// do stuff with games.back()
return games.size()-1;
}
There are countless other ways to pass the object around.
No matter what you choose you have to pass something to identify which Game object you are talking about back into your showGameStatus function, if you plan to have more than one Game object flying around (I assume you do).
auto some_handle = instructor.createGame();
// ... later ...
instructor.showGameStatus(some_handle);
This all holds true, if you want more than one object. Otherwise you might want to just add the object as a member of your Instructor type:
class Instructor {
private:
Game game;
public:
Instructor() : game() {}
// no createGame function, it is superfluous
void showGameStatus() const {
game.some_output_function();
}
};
Just inherit the Instructor Class into the Game Class and do your work...
I have a struct Creature and a struct Game. Game is a "friend" of Creature.
In game I have
vector creatures;
and I add a creature x to that vector thourgh a function called addC
void addc (Creature& c){
creatures.push_back(c);
}
Now I'm in another function "foo" that is a public method of the struct Game.
void foo (Creature& c){
...
}
In that function I need to find another creature from the vector creatures that
matches some information from Creature c.
So I made another public method in Game called fooHelper
void fooHelper (char s, int x, int y){
bool found = false;
for (int i = 0; i < creatures.size() && (!found); ++i){
Creature& c = creatures[i];
if (x == c.x && y == c.y){
c.s = s;
found = true;
}
}
}
however when I check if the second creature's "s" member is being updated, it turns out that
it is not! I don't understand what I'm doing wrong since I'm pushing by references to the vector.
and I'm getting the creature by reference from the vector.
the vector in game looks like this
struct Game{
private:
vector<Creature> creatures;
...
}
struct Creature{
private:
char s;
int x; int y;
...
}
any help would be much appreciated!
This statement:
creatures.push_back(c);
Stores a copy of c into your vector: standard containers have value semantics. If you need reference semantics, you should store pointers into your vector.
Usually it is a good idea to use smart pointers, and which one to use depends on the ownership policy of your application. In this case, based on the information I could get from your question's text, it seems reasonable to let Game be the unique owner of all Creatures in the game (and therefore the only object which is responsible for the lifetime of the owned Creatures, and in particular for destroying them when they won't be needed anymore), so std::unique_ptr should be a good choice:
#include <memory> // For std::unique_ptr
struct Game{
private:
std::vector<std::unique_ptr<Creature>> creatures;
...
};
Your member function addc() would then become:
void addc(std::unique_ptr<Creature> c)
{
creatures.push_back(std::move(c));
}
And a client would invoke it this way:
Game g;
// ...
std::unique_ptr<Creature> c(new Creature());
g.addc(std::move(c));
Your foohelper() function, on the other hand, would be rewritten into something like this:
void fooHelper (char s, int x, int y) {
bool found = false;
for (int i = 0; i < creatures.size() && (!found); ++i){
std::unique_ptr<Creature>& c = creatures[i];
if (x == c->x && y == c->y) {
c->s = s;
found = true;
}
}
}
Finally, your class Game could return non-owning raw pointers (or references) to clients requiring access to the stored creatures.
When you push your creature reference into the vector, it's making a copy. It's a vector of type "Creature", and so it's making a copy from the reference that you give it. One solution would be to keep a vector of creature pointers.
edit - this question helps explain things a little better than I was able to on why you can't have a vector of references: Why can't I make a vector of references?
I'm currently pondering how should I go about making a 2D vector array for a sort of a game board.
The board should be vectors because the size can vary, and each "square" should contain information about what objects are in that square.
The problem is that there can be overlapping objects, and the objects may not be the same type or class.
This is what I'm currently considering: (pseudo code)
struct Square {
vector<enum type>;
vector<pointers to objects>;
};
vector< vector <Square> >;
And the pointer's would point to different vector arrays each holding specific objects.
I'm unsure how to make such functionality or if this is even possible, and I'm seriously thinking this might be more complicated then it needs to be..
Some objects must be classes, but I could make all the types of objects in the game board classes that inherit from one master class.. But in the end the objects are completely different so I'm not sure if that makes much of a difference.
Am I just being blind and missing a easier way to do what I'm trying to do: 2D array holding different types of elements that can also overlap in the array?
I'd really appreciate any help, snippets or insight.
Notes:
Board size won't chance after creation.
Objects must be able to move around in the board.
Here's what I would suggest.
#include <boost/shared_ptr.hpp>
class GameObject {
public:
virtual ~GameObject() {}
enum Type {
FOO,
BAR
};
virtual Type type() const = 0;
virtual std::string name() const = 0;
virtual void damaged() {}
};
class FooObject : public GameObject {
public:
Type type() const { return FOO; }
std::string name() const { return "Foo object"; }
void damaged() {
std::cout << "Foo was damaged!" << std::endl;
}
};
class BarObject : public GameObject {
public:
Type type() const { return BAR; }
std::string name() const { return "Bar object"; }
// Bar object doesn't respond to damage: no need to override damaged()
};
class Square {
std::vector<boost::shared_ptr<GameObject> > objects;
};
class Board {
// Details of the implementation here not important, but there
// should be a class to hide them.
Square* squares;
int width, height;
Board(int width, int height) :
squares ( new Square[ width * height ] ),
width ( width ),
height ( height )
{
}
~Board() {
delete [] squares;
}
Square& square(int x, int y) {
if( x < 0 || x >= width || y < 0 || y >= height ) {
throw std::logic_error( "accessed square out of bounds" );
}
return squares[ x + width * y ];
}
};
Summary:
Have a single base class for all sorts of objects that can be placed on a game board.
A class of this type must have a virtual destructor, even if it's trivial. This is because you will be deleting things through GameObject pointers.
If it's necessary to distinguish the game objects, use a virtual method returning a 'type' value.
As far as it's not necessary to use it, don't use that type value, but use other virtual methods that do meaningful things instead. Using the type value (and then generally casting to the subtype) should be considered a last resort. For instance (inventing details about your game freely):
Every object has a name that shows when you put the cursor over it. This is returned in name().
Events in the game may cause 'damage' an object. This only applies to some sorts of objects, so the default action on damaged() is to do nothing. Foo-objects, which respond to damage, override this with an actual action.
However you implement the board, hide your exact implementation away in a class. (Don't take my code as an indication that you shouldn't use vector<> for this, that's definitely fine. I have a slight personal preference against vector< vector<> > here, but that's not too bad either.)
Use shared pointers for the game objects.
Boost has a great and widely used implementation.
If you can't use shared pointers, control the lifetime of your game objects outside the Square class (say, in a master list of all game objects in the Board class), and then use raw pointers in the Square class.
If you do use shared pointers, and it's the first time you do, briefly read up on them first. They're not magic, you need to beware of certain things such as circular references.
Depending on your needs, you may want to have a "backlink" in GameObject to the squares, or the coordinates of the squares, that contain pointers to that GameObject. This will allow you to easily remove objects from the board and move them around.
Hi I know there are a lot of similar questions but I've been through them and I can't seem to make my function work. I need to return a pointer to a 2D array. So far I am using this code:
(This code is a function in Level.cpp)
TileType* CLevel::getTiles()
{
TileType (*matrix_ptr)[31] = tiles;
return *matrix_ptr;
}
(TileType is an enum) This function is just returning one row and I obviously need both. Any suggestions?
Header file Level.h:
class CLevel
{
private:
list<CBox> boxes;
TileType tiles[GRID_HEIGHT][GRID_WIDTH];
CPlayer player;
public:
CLevel();
~CLevel();
CPlayer* getPlayer();
list<CBox>* getBoxes();
TileType** getTiles();
};
Don't define getTiles().
You are completely breaking the encapsulation of the class. This doesn't always matter but in this case the C/C++ 2D array is not a fit structure for passing outside where its dimensions might not be known.
So define your operations on tiles as methods of CLevel.
What you should do is either this:
// Class declaration
class CLevel
{
public:
TileType (*getTiles())[GRID_WIDTH];
TileType tiles[GRID_HEIGHT][GRID_WIDTH];
//...
};
// Implementation
TileType (*CLevel::getTiles())[GRID_WIDTH]
{
return tiles;
}
or this:
// Class declaration
class CLevel
{
public:
TileType (&getTiles())[GRID_WIDTH][GRID_HEIGHT];
TileType tiles[GRID_HEIGHT][GRID_WIDTH];
//...
};
// Implementation
TileType (&CLevel::getTiles())[GRID_WIDTH][GRID_HEIGHT]
{
return tiles;
}
It's a bit of a complicated declaration but read it inside out: in both cases getTiles() is a function that returns a reference to a 2D array of tiles (the example shows two forms of syntax). By calling getTiles() you're actually referring to tiles. You can even call the function it in this way: getTiles()[i][j].
If you want to return a pointer to a 2d array, then your function declaration should be:
TileType** CLevel::getTiles()
And your return should be matrix_ptr, not its pointer content (which is a one-dimension array).
return matrix_ptr;
In C++ I have an array of pointers to Player objects and want to fill it with Fickle objects where Fickle is a class that is derived from Player. This is because I want a general Player array that I can fill with different objects from different classes that all are derived from the Player class.
How can I do this?
I create an array of pointers to Player objects
Player ** playerArray;
Then initialize the array to a certain size
playerArray = new Player *[numPlayersIn];
But then the following does not work for some reason:
playerArray[i] = new Fickle(0);
How can I fill the playerArray with Fickle objects (Fickel is a class derived from Player) ?
Thanks.
UPDATE:
I get the error message (in Eclipse IDE):
expected ';' before 'Fickle'
I think it might be something to do with the definition of Fickle.
The Fickle.hpp file contains:
#pragma once
#include "player.hpp";
class Fickle: public Player {
public:
// constructor
Fickle(int initChoice){
choice = initChoice;
}
}
Is this OK or is there a problem with this?
The Player class header file has:
class Player {
private:
public:
int getChoice();
int choice; // whether 0 or 1
virtual void receive(int otherChoice); // virtual means it can be overridden in subclases
};
The receive method will be overridden in Fickle and other classes derived from the Player class
UPDATE 2:
OK I think the error is actually due to a different part of the code.
Player defines a method receive:
virtual void receive(int otherChoice);
That should be overridden by the subclass Fickle but the definition in Fickle:
void Fickle::receive(int otherChoice) {}
gives the error:
no 'void Fickle::receive(int)' member function declared in class 'Fickle'
But I don't know why this is because receive is defined in the Player class?
While you probably should be using a vector instead, there's no real reason a dynamically allocated array can't work. Here's a bit of working demo code:
#include <iostream>
class Player {
public:
virtual void show() { std::cout << "Player\n"; }
};
class Fickle : public Player {
public:
virtual void show() { std::cout << "Fickle\n"; }
};
int main() {
Player **p = new Player *[2];
p[0] = new Player;
p[1] = new Fickle;
for (int i=0; i<2; i++)
p[i]->show();
for (int i=0; i<2; i++)
delete p[i];
delete [] p;
return 0;
}
It looks like you forgot a semicolon at the end of Fickle class:
class Fickle: public Player {
// ...
}; // <---- this semicolon
Maybe somewhere else.
UPDATE 2: When you override a virtual function in the derived class you must declare it there too.
If it's not compiling correctly, then you probably didn't #include the header that defines Fickle in the same source file you have that code. Usually an error like that means the compiler doesn't know what Fickle is.
Does Fickle have a constructor that accepts an int or pointer type? Is it privately derived from Player? Otherwise it looks like this should work.