Pointer of class to void* - c++

i am working on a rpg games with class
i created a struct call Character with ActionList* which store the instance.
GeneralPlayer is a class where there have still a bunch of other players classes inherited it.
This is my header file:
class Battle
{
public:
struct Character
{
char type;//monster or player?
bool alive;
void*instance;//pointer to instance
};
Battle(GeneralPlayer*,AbstractMonster*,int,int,int);
Battle(GeneralPlayer*, AbstractMonster*, int, int);
private:
Character *ActionList;
};
i was trying to convert GeneralPlayer* to void*. However seems like the code doesnt work as i thought. P and M are array of pointers of those player classes.
Battle::Battle(GeneralPlayer*P, AbstractMonster*M, int a, int b, int c)
{
a = numP;
b = numM;
c = turn_limit;
ActionList = new Character[numP + numM];
P = new GeneralPlayer[numP];
for (int i = 0; i < numP; i++)
{
ActionList[i] = static_cast<void*>(P[i]);
ActionList[i].type = 'p';
}
for (int i = numP; i < numP+numM; i++)
{
ActionList[i] = static_cast<void*>(M[i]);
ActionList[i].type = 'm';
}
}
it keeps showing the error C2440. I wish can solve my problem with anyone helps thank you.

You are trying to convert object into pointer, use the & operator to get the pointer in question.
ActionList[i] = (void*)&P[i];
ActionList[i] = (void*)&M[i];

One of the problems here is that the Character structure is not a parent of either GenericPlayer or AbstractMonster. It seems that the Character::instance member should be pointing to the player or monster, which means your code should be something like
ActionList[i].type = 'p';
ActionList[i].alive = true;
ActionList[i].instance = &P[i];
This is assuming that the list of players is already initialized by the caller of the Battle constructor, then you should not allocate a new array of players, so the P = new GenericPlayer[numP]; statement should be removed.
It should be noted that having something like you do, a "generic pointer" (what void * is) and then a member saying what type it's really pointing to is considered bad design. Instead you would have a common base-class for both monsters and players, and use a pointer to that. Then with the correct use of polymorphism and virtual member functions you don't need the type field. And then it's easy to refactor the code to use some other means of telling if a player or monster is alive or not, and then you don't need the Battle::Character class at all, and could use an array of pointers to the common base class instead, thus simplifying the code a bit, which is very good for maintainability.
There are a few other problems with the code as you show it, things that will cause problems later at runtime.
One problem is that in the loop iterating over the monsters, you initialize o to numP and loop up to numP + numM, but if the array M doesn't contain numP + numM elements you will go out of bounds.
Instead I suggest you do e.g.
for (int i = 0; i < numM; i++)
{
ActionList[i + numP].type = 'm';
ActionList[i + numP].alive = true;
ActionList[i + numP].instance = &M[i];
}

Related

pointer attribute changes when reexamined

I am new to C++, currently working on a networking project, faced an unusual error with a vector of object pointers.
State class:
struct State
{
public:
int reject_percent_;
int fill_percent_;
int partial_fill_;
bool is_logged_in_;
struct order
{
long id;
long price;
int quantity;
bool is_filled = false;
bool is_partially_filled = false;
};
std::vector<order *> orders;
};
pushing into vector: (here state is an object of State struct)
State::order* o;
o->id = (obj->ClOrdID); // obj->ClOrdID = 1
o->price = (obj->Price); // obj->Price = 1
o->quantity = (obj->OrderQty); // obj->OrderQty = 1
std::cout<<o->id<<"\n"; //outputs 1
state->orders.push_back(o);
in other function:
State::order* ord = NULL;
for (int i = 0; i < state->orders.size(); ++i)
{
std::cout<<((state->orders).at(i)->id)<<"\n"; //outputs :: 93893845689152
std::cout<<((state->orders).at(i)->price)<<"\n"; //outputs :: 93893845689184
std::cout<<((state->orders).at(i)->quantity)<<"\n"; //outputs :: 869246848
if(obj->ClOrdID==(state->orders).at(i)->id)
{
ord=(state->orders).at(i);
break;
}
}
I know this is not a minimal reproducible example, but I think this might be a trivial error that I don't see, the code is big and will take a long time shortening, so please bear with me, can you just point out what might cause this problem, as the values seem to be junk values of the datatypes.
You didn't allocate memory for the order and you didn't initialize the pointer
State::order* o;
Dereferencing this pointer to write into it
o->id = (obj->ClOrdID); // obj->ClOrdID = 1
o->price = (obj->Price); // obj->Price = 1
o->quantity = (obj->OrderQty); // obj->OrderQty = 1
to read from it
std::cout<<o->id<<"\n"; //outputs 1
or copying it
state->orders.push_back(o);
causes undefined behavior. Your program could crash, everything could seem correct or your computer could order a pizza.
It's difficult to say what's the best way to solve this problem with just some code snippets. One way is to change std::vector<order *> orders; to std::vector<order> orders;. Another way is to use smart pointers.
State::order* o;
o->id = (obj->ClOrdID);
The pointer has an indeterminate value. The behaviour of indirecting through this uninitialised pointer is undefined.
You should probably use this instead:
std::vector<order> orders;
So that the vector contains order instances.

C++ - Creating pointers to elements of an array containing pointers to class objects

I'm new to C++ and programming in general and am trying to learn by creating a sort of game as I go along. I can't find any information on how to achieve what I need to do.
I have created the following code, which I believe creates new objects of class Player off the heap, and creates pointers to these objects in an array.
int playerObjects(int n, int gameMode)
{
Player* playerArray = new Player[n];
for (int i = 0; i < n; i++)
{
playerArray[i].balance = 50;
playerArray[i].score = 0;
playerArray[i].playerNum = (i+1);
int m = (i+1);
playerArray[i].playerName = playerArray[i].playerN(m);
string playerNam = playerArray[i].playerName;
playerArray[i].playerAge = playerArray[i].playerA(playerNam);
playerArray[i].teamNum = 0;
}
}
where n is the number of players (from 1-4).
The class Player I have created myself:
What I now want to do is return to the calling function, main(), and still be able to access and modify these objects. I cannot figure out how. I have attempted to create pointers to each element of the array, like so:
Player** pOne = playerArray[0];
Player** pTwo = playerArray[1];
Player** pThree = playerArray[2];
player** pFour = playerArray[3];
which I think declares pOne to be a pointer to a pointer to an object of class Player (the array element), however, this throws the error:
cannot convert 'Player' to 'Player**' in initialization
doing it like this throws the same error, but in assignment rather than initialization (obviously):
Player** pOne;
pOne = playerArray[0];
How do I do it?
And, once I have done it, how do I then pass this from main() to other functions that also need to have access to these?
Would it be better to declare the array globally?
Thanks
The easiest way is probably to just return the pointer.
Player* playerObjects(int n, int gameMode)
{
Player* playerArray = new Player[n];
...
return playerArray;
}
Alternatively if you want to keep the return value as an int, you can pass a pointer to a pointer to the function. You can then create the array in the specified pointer.
int playerObjects(int n, int gameMode, Player** playerArray)
{
*playerArray = new Player[n];
for (int i = 0; i < n; i++)
{
*playerArray[i].balance = 50;
*playerArray[i].score = 0;
...
}
}
You can call this function by doing:
Player* playerArray;
playerObjects(n, gameMode, &playerArray)
And then access the items of playerArray as usual:
playerArray[0].xyz;
Don't forget that after you've allocated memory with with new[], you need to delete it with delete[] when you're finished with it.
The function musts to return (either as the return value or as a referenced parameter) the pointer to the first element of the created array. Thus in main you can use the pointer with the subscript operator.
Or more better approach is to use standard container std::vector<Player> and return it from the function.
playerArray[0] will return object of type Player, so typecast operation you are doing is incorrect.
If you want to use this array in main() then you can return playerArray from function playerObjects().

Getting address of pointer from a method returning pointer

Suppose I have:
class Map {
public:
Map();
vector<Territory>* getTerritories();
};
vector<Territory>* Map::getTerritories()
{
vector<Territory> t;
for (int i = 0; i < 8; i++) {
Territory ter;
ter.setName("Territory " + std::to_string(i + 1));
t.push_back(ter);
}
return &t;
}
Now in another class, I want to get the same vector I created in the getTerritories() method.
Here's how:
void GameSetup::assignTerritories()
{
vector<Territory> * generatedTeritories = (*map).getTerritories(); // dereferenced
}
I'm not getting a compiler error because they're both pointers. But somehow I cannot seem to access my Territory objects within my vector by simple iteration like you would normally do over a vector.
At this point, (*map).getTerritories() gets a pointer to my territory vector (if I try to follow). Now suppose I want to make an 'alias' of some sort of this pointer I'm returning, how would I do so? Is it possible to get the address of a pointer? I asked myself this question and tried the following:
vector<Territory> * generatedTeritories = &(map->getTerritories());
but that obviously didn't work. I'm not sure what else to do and I've been going in circles.
Please, forget pointers here. getTerritories() was returning a pointer to a local object. This object is destroyed after the function return. You just need to return the object and you'll then find in back in your generatedTeritories variable.
class Map {
public:
Map();
vector<Territory> getTerritories();
};
vector<Territory> Map::getTerritories()
{
vector<Territory> t;
for (int i = 0; i < 8; i++) {
Territory ter;
ter.setName("Territory " + std::to_string(i + 1));
t.push_back(ter);
}
return t;
}
void GameSetup::assignTerritories()
{
vector<Territory> generatedTeritories = (*map).getTerritories(); // dereferenced
}
Now you can get the address of the vector like that:
vector<Territory>* addressOfGeneratedTeritories = &generatedTeritories;
But it's only safe to use it while generatedTeritories remains alive (in the code above, it's alive untill assignTerritories() execution ends as it is a local variable of this function). To make it persistent, it has to be an attribute of another object...it will then remain alive untill the parent object gets destroyed...and so on. It could allso be a global variable which is definitely not recommended (it's a bad practice, object oriented design always have alternatives to that).
BTW, I would recommend that you follow some tutorials about C++ before starting to code a game.....;-)

Exc_bad_access with pointers

I have been working in a project using matrices and graphs. The problem is when I compile it, the next line pops up:
EXC_BAD_ACCESS (code=2, address=0x7ffff5f3ffff8)
It appears in the next method; which is a constructor of my class:
GrafoMatriz::GrafoMatriz(){
maxVerts = 1;
GrafoMatriz(maxVerts);
}
typedef int * pint;
class GrafoMatriz {
...
int maxVerts;
int numVerts;
Vertice * verts; // there's another class Vertice
int ** matAd;
GrafoMatriz();
GrafoMatriz(int mx);
...
}
GrafoMatriz::GrafoMatriz (int mx){
maxVerts = mx;
verts = new Vertice[mx];
matAd = new pint[mx];
numVerts = 0;
for (int i = 0; i < mx; i++)
matAd[i] = new int[mx];
}
I have been reading about possible problems and it could be something wrong about pointers:
The pointer could have never been initialized.
The pointer could have been accidentally written over because you overstepped the bounds of an array.
The pointer could be part of an object that was casted incorrectly, and then written to.
Any of the above could have corrupted a different pointer that now points at or near this pointer, and using that one corrupts this one (and so on).
I guess it's something about my pointer pint, but I am new to C++. So, I haven't been able to fix it. By the way0, I'm using Xcode 6.4 on an Intel Macbook Pro.
As mentioned by #kuroineko in the comments, you cannot call a constructor from another constructor in C++. If you use C++11 (or a later standard) then you can use delegating constructors. Otherwise you might want to define an initialization function, for example, like this:
void GrafoMatriz::Initialize(int mx){
maxVerts = mx;
verts = new Vertice[mx];
matAd = new pint[mx];
numVerts = 0;
for (int i = 0; i < mx; i++)
matAd[i] = new int[mx];
}
Then you can call this initialization function from your different constructors:
GrafoMatriz::GrafoMatriz(){
Initialize(1);
}
GrafoMatriz::GrafoMatriz (int mx){
Initialize(mx);
}
As far as I can tell, the rest of the shown code should compile. I don't know if the code related to your variable matAd is correct, but at least it doesn't crash for me.

Using an Array on a Polymorph design

I am just starting to really understand Polymorphism, but still this is a new topic for me.
So here is my Problem: I have to classes, enemy and Bankrobber. However Bankrobber inherits from
enemy. I tried to make an array of 10 Bankrobbers. A global function should then use all members of the array to do something, well I guess this is a worthless description, so here is the code:
void UpdateEnemies(Enemy * p_Enemy, int counter) {
for(unsigned int i = 0;i < counter;i++) {
p_Enemy[i].Update();
}
}
int main(void) {
BankRobber EnemyArray[10];
Enemy * p_Enemy = new BankRobber(13,1);
UpdateEnemies(EnemyArray,10);
system("PAUSE");
};
I apologize for any language mistakes. I am not a native speaker
My actual Problem: This code is just for practicing, so the purpose is just to see 10 times Update on the console, for each member of the Array. So the function UpdateEnemys should call all the enemy.update functions. The method with the type casting is not exactly what I want, cause it is not dynamicly anymore, as there will be more enemy later on. Not only Bankrobbers.
Polymorphism only works on single objects, accessed by a reference or pointer to a base class. It does not work on an array of objects: to access array elements, the element size must be known, and that's not the case if you have a pointer to a base class.
You would need an extra level of indirection: an array of pointers to single objects, along the lines of
void UpdateEnemies(Enemy ** p_Enemy, int counter) {
for(unsigned int i = 0;i < counter;i++) {
p_Enemy[i]->Update();
}
}
int main() {
// An array of Enemy base-class pointers
Enemy * EnemyArray[10];
// Populate with pointers to concrete Enemy types
for (unsigned i = 0; i < 9; ++i) {
EnemyArray[i] = new BankRobber;
}
// Of course, the array can contain pointers to different Enemy types
EnemyArray[9] = new Dragon;
// The function can act polymorphically on these
UpdateEnemies(EnemyArray,10);
// Don't forget to delete them. Enemy must have a virtual destructor.
for (unsigned i = 0; i < 10; ++i) {
delete EnemyArray[i];
}
}
You should also consider using RAII types, such as containers and smart pointers, to manage these dynamic resources; but that's beyond the scope of this question.
Declaring an array of BankRobber like this
BankRobber EnemyArray[10];
But than acessing them through the base class pointer like this
Enemy * p_Enemy;
p_Enemy[i].Update();
Wouldn't work. That's because indexing an array p_Enemy[i] will be done by using the offcet sizeof(Enemy)
But sizeof(BankRobber) is probably bigger than from sizeof(Enemy), so p_Enemy[i] will end up in the wrong place
You should use a vector of pointers instead, like
std::vector<Enemy*>
That way you can also use polymorphism if you add pointers to different objects into the vector. And you don't need to pass the ugly int counter around
Indeed you didn't say exactly what is the problem.
Did you try casting inside your code? Something like:
void UpdateEnemies(Enemy * p_Enemy, int counter) {
BankRobber *pRobber = (BankRobber*)p_Enemy;
for(unsigned int i = 0;i < counter;i++) {
pRobber[i].Update();
}
}