I am implementing a simple board game (Breakthrough) using OpenGL (plus GLUT and GLUI).
I'm thinking of implementing a Board class, which will have a vector<vector<Cell> > as one of its attributes. Cell represents a space in the game board. It can contain a GameObject. GameObject will be a pure abstract class. It mandates that its derivative classes implement render(), for example. Possible derivative classes will be:
Blank, representing an empty space
Pawn, representing a pawn (the only possible pieces in Breakthrough)
The board will be rendered by first rendering the board, then iterating through each Cell, getting its contents and calling render() for each of them.
The only possible way I can think of to achieving this is making the GameObject in Cell a pointer (board[y][x].getContents()->render(), where getContents() returns the GameObject*)
Is this the best way to do this? Is this an appropriate usage of pointers?
Let me promote my comment into an answer. This doesn't mean that it's in any sense complete, only that this allows me to spell out some code examples. My original comment:
That's OK, though you probably would do better with a std::unique_ptr<GameObject> or a std::shared_ptr<GameObject> so you don't get lost amids the manual lifetime management issues. Finally, how about a flat 1-D array accessible in strides?
Here's how I might go about this:
#include <vector>
#include <memory>
struct GameObject { virtual void render() const = 0; virtual ~GameObject() { } };
class Cell
{
std::unique_ptr<GameObject> m_go;
public:
void render() const { m_go->render(); }
Cell() : m_go(new BlankCell) { }
// more functions to reassign the cell value etc.
};
class Board
{
std::vector<Cell> m_board;
std::size_t m_length;
public:
Board(std::size_t length) : m_board(length * length), m_length(length) { }
Cell & cell(std::size_t i, std::size_t j) { return m_board(j + i * m_length); }
Cell const & cell(std::size_t i, std::size_t j) const { return const_cast<Board*>(this)->cell(i, j); }
// more...
}
Yes.
Also, maybe you should use another container for your cells (some kind of matrices or so)
Related
I am creating an abstract geometry class that has children classes. However, I want that the class RightCircularCone also has its own private variables that define its apex coordinates, such that the abstract class is not unnecessary big in memory size for objects of type Sphere that don't need storage of apex variables.
However, I can't seem to access the functions and variables of RightCircularCone when I load them from a container that uses smart pointers, as it keeps being defined as its parent class Shape. Can anyone see what is going wrong?! Appreciate it!
/* shapes.hpp */
class Shape{
public:
unsigned int color;
float radius;
float x,y,z;
public:
void SetSpatial(float radius, float x, float y, float z);
unsigned int GetColor(void);
void SetColor(unsigned int color);
virtual bool PointInside(const std::array<double,3> &point)=0;
};
class RightCircularCone : public Shape{
private:
float Ax,Ay,Az;
public:
bool PointInside(const std::array<double,3> &point);
void SetApex(float x, float y, float z);
void PrintApex();
};
class Sphere : public Shape{
public:
bool PointInside(const std::array<double,3> &point);
};
The classes defined above are used in another .cpp file where methods of a class are defined:
#include "../../include/part.hpp" /* includes shapes.hpp in turn */
void Part::ReadPartFile(std::string partfile){
try{
std::ifstream dataFile;
dataFile.open(partfile);
//do checks, error badbits etc...
std::string word;
unsigned int counter=0;
while(!dataFile.eof()){
dataFile >> word;
if(word == "sphere"){
auto newSphere = std::make_shared<Sphere>();
// load variables into objects from file by checking each word by using setColor and setSpatial
shapeList[counter++] = newSphere;
} else if(word == "rccone"){
auto newRccone = std::make_shared<RightCircularCone>();
// load variables into objects from file by checking each word by using setColor and setSpatial and setApex
shapeList[counter++] = newRccone;
}
}
dataFile.close();
} catch(std::ifstream::failure e) {
//do exception handling here if necessary
}
Now, when I use an iterator over the map std::map<unsigned int, std::shared_ptr<Shape> > shapeList; as defined in part.cpp I can never access the methods of children classes Sphere and RightCircularCone as the map returns a type of Shape, even though I used a smart pointer!!!
Anybody knows why and a potential fix (or neater way to set up the classes)??
Thanks!
//EDIT:
This is the error I get:
error: no member named 'PrintApex' in 'Shape'
iterator->second->PrintApex();
Think about it. You create a vector of shared_ptr of Shape. As far as the vector is concerned you are storing Shape instances in it, not Sphere or whatever.
Now, you happen to initialize your Shape instance with a Sphere and you store the ptr of that Sphere into the vector. Next item is a RightCircularCone, again stored as a Shape.
You access the first element, and as far as the compiler is concerned at THAT point, you only have a Shape. It cannot deduce the actual type as this happens at runtime. So, as far as the compiler is concerned you have a Shape instance with whatever the Shape class contains.
Now, you need to somehow inform the compiler about the type you want to work with, so it can find the methods you want to access. For that, you use dynamic_cast to specify the intent that this is a Sphere and you should have access to Sphere members.
More details about dynamic_cast, here http://en.cppreference.com/w/cpp/language/dynamic_cast
Edit. A note about design.
In principle, you want to offload as much to the compiler. If there is something that compiler can do, let him do it. So, if you want to do something different for each subclass of Shape, instead of checking a string literal for the Shape type you could use virtual specialized functions that act on a specific type. E.g.
virtual void printMe(Sphere & sphere) {
cout << "This is a sphere with radious x" << endl;
}
virtual void printMe(RightCircularCone & cone) {
cout << "This is a cone" << endl;
}
//and you use like
for (auto & shape: shapes) { printMe(shape); }
//and the correct functions are resolved automagically
it may seem a bit more work, but in the long run it is actually simpler as you offload the picking of the functionality to someone else.
I am currently creating a class that has to be derived from std:: vector. I realize its probably bad to do this but I'm required to. Now my question is how do you access the created vector in the member functions to basically make the class access itself like a regular vector of integers? For example I am looking for the equivalent of myVector.at(0) to return the first term in the vector. Also, the size of the vector should always be 6. Here is the code I have so far:
class aHistogram : public vector<int>
{
public:
aHistogram(); //default constructor for histogram class
void update(int face); //Function to update histogram
void display(int maxLengthOfLine); //Displays histogram to the scale of maxLengthOfLine using x's
void clear();//Function to clear histogram bin counts
int count(int face) const; // Function to return number of times a face has appeared
private:
int numx, m, j; //Variables used in functions
};
#endif
The function that requires the class to access itself is below, I know there is no vector called "myVector" but what I'm lost about is the equivalent syntax to be able to perform the operation.
void aHistogram::clear()
{
//Clears bin counts to 0
myVector.at(0) = 0;
myVector.at(1) = 0;
myVector.at(2) = 0;
myVector.at(3) = 0;
myVector.at(4) = 0;
myVector.at(5) = 0;
}
If the function in question isn't overridden in the derived class, you
can just call it:
void HistoGram::clear()
{
at( 0 ) = 0;
// ...
}
This is also true for operators, but you'll have to use (*this) as the
left hand operator:
void HistoGram::clear()
{
(*this)[0] = 0;
// ...
}
If the function or operator is overridden, you'll either have to
qualify the function name,
void HistoGram::clear()
{
std::vector<int>::at( 0 ) = 0;
// ...
}
or cast the this pointer to the base class type:
void HistoGram::clear()
{
(*static_cast<std::vector<int>*>( this ))[0] = 0;
// ...
}
But are you sure that you want public inheritance here? You state that
the size of the vector should always be 6. There's no way you can
guarantee that using public inheritance; at the least, you need private
inheritance, and then using declarations for the operations that you
want to support. (I've a couple of cases where I've needed restricted
std::vector like this, which I've implemented using private
inheritance. And sometimes forwarding functions, when for example
I've wanted to expose only the const version of the function.)
Also: there are very, very few cases where std::vector<>::at is
appropriate. Are you sure you don't want [], with the bounds checking
you get in most modern implementations.
Instead of deriving from std::vector, in this case contain one (as a data member).
The problem with deriving is that it's then possible to treat a Histogram instance as just a std::vector, doing things that invalidate assumptions about the values of added data members.
In more technical jargon, with class derivation you have no guaranteed class invariant above the one provided by std::vector.
As a general rule of thumb, think of data member before class inheritance.
Sometimes inheritance is the thing, even inheritance from standard library container classes (e.g., std::stack is designed for inheritance), but not in this case.
About this: the size of the vector should always be 6.
You probably want to forbid some functionality to the user of the class. For example
vector::push_back
vector::pop_back
vector::insert
are functionalities that can change the size of the vector.
You can achive this by making such functions private members in the child class:
class aHistogram : public vector<int>
{
public:
aHistogram(){};
private:
vector<int>::push_back;
vector<int>::pop_back;
vector<int>::insert;
int numx, m, j;
};
Currently I'm reading Stroustrup Programming: Principles and Practice C++. I faced up with this example:
typedef void (*Pfct0)(struct Shape2*);
typedef void (*Pfct1int)(struct Shape2*,int);
struct Shape2{
Pfct0 draw;
Pfct1int rotate;
};
void draw(struct Shape2* p)
{
(p->draw)(p);
}
void rotate(struct Shape2* p,int d)
{
(p->rotate)(p,d);
}
int f(struct Shape2* pp)
{
draw(pp);
return 0;
}
I cannot get what functions draw and rotate actually do.
I know what is typedef, function pointer, -> operator.
As I understand p->draw function will call itself recursively. Am I right?
What practical uses of making such functions as draw or rotate?
It appears to me that Stroustrup is implementing object-like dispatch in pure C. Each Shape2 object has its own draw and rotate methods. Given an arbitrary Shape2 p, draw(p) looks up that p's draw method, and applies it to itself (presumably p would have some other content that draw would read and take action upon.) The function does not call itself recursively unless the particular draw function for p calls draw recursively. This is very much like what p.draw() would do in C++ if Shape2 were a base class.
Functions draw and rotate calls a functions pointed to by members of structure p, and call these functions on a pointer to this structure p.
maybe this will help:
typedef void (*pointer_to_function)(struct Shape2*);
struct Shape2{
pointer_to_function draw;
Pfct1int rotate;
};
void function(struct Shape2* p)
{
(p->draw)(p);
^^^^^^^^^
// this is pointer_to_function so call the function pointed to by it
// with some argument of type struct Shape2*, in example p itself, why not
}
The misleading in this snippet is that we don't see how pointers in objects Shape2 are initialized, but they must be initialized to point to some functions with appropriate signatures before they are passed to global draw and rotate.
Each instance of Shape2 can have its own draw and rotate functions.
If s is a pointer to a Shape,
draw(s);
is the same as
(s->draw)(s);
This could be used to implement something like
drawrect(Shape* s);
drawcircle(Shape* s);
...
Shape shapes[2];
shapes[0].draw = &drawrect;
shapes[1].draw = &drawcircle;
...
for(int i = 0; i < 2; i++) {
draw(&shapes[i]);
}
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.
Vectors if are data of a class should be assigned as private member of that class.
The class should provide the methods to access the vector methods needed.
Now I have my class Snake which encapsulate a snake for the classic game.
typedef std::vector<Polygon4>::const_iterator const_iterator;
enum directions{UP, DOWN, RIGHT, LEFT, IN, OUT, FW, RW };
class Snake
{
private:
enum directions head_dir;
int cubes_taken;
float score;
struct_color snake_color;
V4 head_pos;
std::vector<Polygon4> p_list; //the vector
public:
Snake();
V4 get_head_pos();
Polygon4 create_cube(V4 point);
void initialize_snake();
void move(directions);
void set_head_dir(directions dir);
directions get_head_dir();
void sum_cubes_taken(int x);
int get_cube_taken();
void sum_score(float x);
float get_score();
void set_snake_color();
//vector manipulation functions
const_iterator p_list_begin() const {return p_list.begin();}
const_iterator p_list_end() const {return p_list.end();}
void add_IntToP_list(Polygon4 cube){p_list.push_back(cube);}
void clear_list(){p_list.clear();}
unsigned int get_list_size(){return p_list.size();}
};
I have an other class in my program, the graphic management:
class MyGLBox{
private:
std::vector<Polygon4> p_list;
public:
//do stuff...
//management vectors:
const_iterator p_list_begin() const {return p_list.begin();}
const_iterator p_list_end() const {return p_list.end();}
void add_IntToP_list(Polygon4 cube){p_list.push_back(cube););
void clear_list(){p_list.clear();}
unsigned int get_list_size(){return p_list.size();}
}
Now every frame in the game I need to copy the snake p_list into the MyGLbox p_list. If the vectors were public it would have been pretty easy:
myGLBox.p_list = snake.p_list;
now if they are private:
transfer_function(*MyGLBox box, *Snake snake){
const_iterator cube;
for(cube = snake->p_list_begin(); cube != snake->p_list_end(); cube++){
box->add_InTop_list(*cube);
}
}
is it right what I'm trying to do? Is there a better way to do it? To me the for cycle seems pretty inefficent
If you already have a function
void add_IntToP_list(Polygon4 cube){p_list.push_back(cube););
for adding a single element, you can add another overload for adding a range of elements
void add_IntToP_list(vector<Polygon4>::const_iterator first,
vector<Polygon4>::const_iterator last)
{ p_list.insert(p_list.end(), first, last); }
and then call that with the range you want to add, maybe
box->add_IntToP_list(snake->p_list_begin(), snake->p_list_end());
You could try using a friend function:
void transfer_function(MyGLBox * box, Snake * snake )
{
box->p_list = snake->p_list;
}
// in class MyGlBox
friend void transfer_function(MyGLBox *, Snake *);
// in class Snake
friend void transfer_function(MyGLBox *, Snake *);
But if you have multiple such scenarios, this can easily become unmanageable.
Alternatively, you could still expose the vector directly via a get member. E.g:
// in class MyGLBox
std::vector<Polygon4> & get_p_list( )
{
return p_list;
}
It's not necessarily always "bad" if you return the vector itself - since you expose a lot of the vector's functionality anyways, it's not like the user has been given unwanted control over the data.
It seems pretty clear that friendship violates the programming exercise. I think your method is correct in that it provides the accessors to the private vector, and I agree, it is inefficient copying all that data. One optimisation you can do is to extend the vector:
v.reserve(v.size() + distance(v_prime.begin(),v_prime.end()));
v.insert(v.end(),v_prime.begin(),v_prime.end());
I robbed the code from here.
You have many ways to do it. One way is to friend your other functions so it can access your vector like a public variable.
Another is to make the variable itself public. Some may argue it's not good practice etc, but that's ridiculous. Are you trying to "protect" the vector from yourself?! Is that how confident you are in your own programming? To me, making private is only good for when you are writing a library for others to use not in your own program.
And finally, a remark on what you said. The for loop you presented is not at all inefficient. It is less efficient than using =, true, but adding one by one is also not that bad. vector's amortized performance is O(1). In fact if inserting something was intended to have cost 1, adding in vector has amortized cost 2.