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();
}
}
Related
I went to a job interview today and was given this interesting question.
Besides the memory leak and the fact there is no virtual dtor, why does this code crash?
#include <iostream>
//besides the obvious mem leak, why does this code crash?
class Shape
{
public:
virtual void draw() const = 0;
};
class Circle : public Shape
{
public:
virtual void draw() const { }
int radius;
};
class Rectangle : public Shape
{
public:
virtual void draw() const { }
int height;
int width;
};
int main()
{
Shape * shapes = new Rectangle[10];
for (int i = 0; i < 10; ++i)
shapes[i].draw();
}
You cannot index like that. You have allocated an array of Rectangles and stored a pointer to the first in shapes. When you do shapes[1] you're dereferencing (shapes + 1). This will not give you a pointer to the next Rectangle, but a pointer to what would be the next Shape in a presumed array of Shape. Of course, this is undefined behaviour. In your case, you're being lucky and getting a crash.
Using a pointer to Rectangle makes the indexing work correctly.
int main()
{
Rectangle * shapes = new Rectangle[10];
for (int i = 0; i < 10; ++i) shapes[i].draw();
}
If you want to have different kinds of Shapes in the array and use them polymorphically you need an array of pointers to Shape.
As Martinho Fernandes said, the indexing is wrong. If you wanted instead to store an array of Shapes, you would have to do so using an array of Shape *'s, like so:
int main()
{
Shape ** shapes = new Shape*[10];
for (int i = 0; i < 10; ++i) shapes[i] = new Rectangle;
for (int i = 0; i < 10; ++i) shapes[i]->draw();
}
Note that you have to do an extra step of initializing the Rectangle, since initializing the array only sets up the pointers, and not the objects themselves.
When indexing a pointer, the compiler will add the appropriate amount based on the size of what's located inside the array. So say that sizeof(Shape) = 4 (as it has no member variables). But sizeof(Rectangle) = 12 (exact numbers are likely wrong).
So when you index starting at say... 0x0 for the first element, then when you try to access the 10th element you're trying to go to an invalid address or a location that's not the beginning of the object.
I have these kind of classes:
Game:
class Game {
private:
BoardField*** m_board_fields;
public:
Game() {
m_board_fields = new BoardField**[8];
for (int i = 0; i < 8; i++) {
m_board_fields[i] = new BoardField*[8];
}
}
Game::~Game() {
for (int i = 0; i < 8; i++) {
for (int j = 0; i < 8; j++) {
delete m_board_fields[i][j];
}
delete[] m_board_fields[i];
}
delete[] m_board_fields;
}
}
BoardField:
class BoardField {
private:
ChessPiece* m_piece;
....
public:
BoardField::~BoardField() {
delete m_piece;
}
}
And on the close of the program I get error in ~BordField:
Exception thrown: read access violation.
this was 0xFDFDFDFD.
Did I made my destructors incorrect? What is the best way to clear memory from multidimensional array ?
There is are two fundamental flaws in your design:
there is no clear ownership of the BoardFields: someone create it, someone else deletes it. It can work if you're very cautious but it's error prone.
you do not ensure the rule of 3 (or better 5): if you have any piece of code where you create a copy of either your Game or a of any BoardField the first object that gets destroyed will delete the m_piece pointer, and when the second object gets destroyed, it'll try to delete a second time the same pointer, which is UB.
There is a third important issue: you're over-using raw pointers:
if m_board_fields is a 2d array of fixed size, make it a fixed size array (aka BoardField* m_board_fields[8][8]). If you want to keep its size dynamic, use vectors.
a cell of m_board_field could be a pointer if there's some polymorphism expected. But this seems not the case here, as obviously ChessPiece is the polymorphic class. So better use plain fields instead of pointers (aka BoardField m_board_fields[8][8]).
Finally, instead of using raw pointer to ChessPiece, better use a shared_ptr<ChessPiece> : you don't have to worry about shallow pointer copies and double delete; the shared_ptr will take care of itself and destroy the object if it's no longer used.
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().
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];
}
I have a class called Foo which has a member that is a pointer to a vector of pointers to another class called Bar. I initialise it in the constructor but I'm not sure how to deallocate it in the destructor. I'm still learning. Would appreciate your help. The reason for having this member is so that the scope persists beyond that method i.e. beyond the stack. Thanks.
#include <iostream>
#include <vector>
using namespace std;
class Bar {};
class Foo {
public:
Foo() {
bars = new vector<Bar*>*[10];
for (int i = 0; i < 10; i++) {
bars[i]->push_back(new Bar());
}
}
~Foo () {
for (int i = 0; i < 10; i++) {
// TODO: how to clean up bars properly?
}
}
private:
vector<Bar*>** bars;
};
int main () {
new Foo();
return 0;
}
Update: I appreciate the feedback on all fronts. I'm new to C and C++. Basically I wanted a 2d structure as a class member that would persist for the lifetime of the class. The reason the outer structure is an array is because I know how big it needs to be. Otherwise I was previously using vector of vectors.
This isn't even allocated properly. You allocate an array of pointers to std::vector<Bar*>, but never any std::Vector<Bar*>.
The best thing to do is just something like std::vector<std::unique_ptr<Bar>> or even std::unique_ptr<std::vector<std::unique_ptr<Bar>>> or something like that. What you've got is just WTF.
Or std::unique_ptr<std::array<std::unique_ptr<std::vector<std::unique_ptr<Bar>>>, 10>>.This is an exact match (but self-cleaning).
The number of pointers is a bit ridiculous, as all they are doing is causing confusion and leaks, as evident from non-proper initialization and the question's title. You don't actually need any pointers at all, and don't have to worry about any cleanup.
For a 2D array with the first dimension passed into the constructor, you can use a vector of vectors:
std::vector<std::vector<Bar>> bars;
To initialize the outer vector with the passed in size, use an initializer:
Foo(size_t size)
: bars(size) {}
When the object is destroyed, bars and all of it elements are as well, so there's no chance of forgetting to clean up or doing so improperly.
If performance is an issue, this can be translated into a sort of Matrix2D class that acts like a 2D array, but really only has an underlying 1D array.
EDIT: In the case of a 2D structure (and you said you know how big your 2D structure needs to be, so we'll assume that the 10 in your loops is the size of the 2D array you desire.
#include <iostream>
#include <vector>
using namespace std;
class Bar {
public:
int BarInfo;
};
class Foo {
public:
Foo() {
// Allocates 10 vector spots for 10 bar elements - 100 bars, 10 x 10
for (int i = 0; i < 10; i++) {
// Puts 10 bars pointer at the end;
// Heap-allocated (dynamically), which
// means it survives until you delete it
// The [10] is array syntax, meaning you'll have 10 bars
// for each bars[index] and then
// you can access it by bars[index][0-9]
// If you need it to be more dynamic
// then you should try vector<vector<Bar>>
bars.push_back(new Bar[10]);
}
}
Bar* operator[] (int index) {
return bars[index];
}
~Foo () {
// Cleanup, because you have pointers inside the vector,
// Must be done one at a time for each element
for (int i = 0; i < bars.size(); i++) {
// TODO: how to clean up bars properly?
// Each spot in the vector<> contains 10 bars,
// so you use the array deletion
// and not just regular 'delete'
delete[] bars[i]; // deletes the 10 array elements
}
}
private:
// vector might not be a bad idea.
vector<Bar*> bars;
};
This is the main I have for testing the code written, and it works like you would think a 2D array should work:
int main ( int argc, char* argv[] ) {
Foo foo;
// Bar at 1st row, 2nd column ( row index 0, column index 1 )
// Bar& is a reference
Bar& bar12 = foo[0][1];
bar12.BarInfo = 25;
int stuffInsideBar = foo[0][1].BarInfo; // 25
return 0;
}
I hope that helps and gets you closer to what you're doing. I've used a technique here that might go over a starters head to make the Foo class behave like you would think a 2D array would. It's called operator overloading. It's a powerful feature in C++, so once you master more basics it might be useful to you in your future projects or current one. Good luck!
~~~~~~~~~~~~~~~~~~~~~~~
OLD ANSWER BEFORE EDIT
~~~~~~~~~~~~~~~~~~~~~~~
It appears you're doing far too much indirection. While another person's answer shows you how to clean up what you've managed to do, I think you could benefit from changing how exactly you're handling the class.
#include <iostream>
#include <vector>
using namespace std;
class Bar {};
class Foo {
public:
Foo() : bars() {
// bars is no longer a pointer-to-vectors, so you can just
// allocate it in the constructor - see bars() after Foo()
//bars = new vector<Bar>();
for (int i = 0; i < 10; i++) {
// Puts 1 bar pointer at the end;
// Heap-allocated (dynamically), which
// means it survives until you delete it
bars.push_back(new Bar());
}
}
~Foo () {
// Cleanup, because you have pointers inside the vector,
// Must be done one at a time for each element
for (int i = 0; i < 10; i++) {
// TODO: how to clean up bars properly?
// TODOING: One at a time
delete bars[i]; // deletes pointer at i
}
}
private:
// You don't need to ** the vector<>,
// because it's inside the class and
// will survive for as long as the class does
// This vector will also be copied to copies of Foo,
// but the pointers will remain the same at the time
// of copying.
// Keep in mind, if you want to share the vector, than
// making it a std::shared_ptr of a
// vector might not be a bad idea.
vector<Bar*> bars;
};
If you pass the class by reference into functions, than the vector<Bar*> inside the class won't copy itself or delete itself, making it persist past a single stack frame.
In your main, this should clean up properly and is a lot easier to keep track of than vector** . However, if for some reason vector** is required, than home_monkey's answer should help you more.
I think there is an issue with allocation. The line
new vector <Bar*> * [10]
will give you an array of points to objects of type vector <Bar*> * and you
will need to allocate some additional memory for your vector <Bar*> type.
I've had a go,
Foo()
{
bars = new vector<Bar*>*[10]; // A.
for (int i = 0; i < 10; i++)
{
bars[i] = new vector<Bar*>; // B. Extra memory assigned here.
bars[i]->push_back(new Bar); // C.
}
}
To free resources, you'll have to reverse the above
~Foo ()
{
for (int i = 0; i < 10; i++)
{
// I'm assuming that each vector has one element
delete bars[i][0]; // Free C
delete bars[i]; // Free B
}
delete [] bars; // Free A
}
I don't believe you're even allocating it properly. To undo what you've done so far, all you'd have to do is:
for(int i=0; i < 10; ++i)
while(bars[i]->size > 0)
{
delete *bars[i]->front();
pop_front();
}
delete[] bars;
But, you need to allocate each of the vectors themselves, for instance in the constructor:
for(int i=0; i<10; ++i)
bars[i] = new vector<Bar*>();
Which would require you change the destructor to:
for(int i=0; i < 10; ++i)
{
while(bars[i]->size > 0)
{
delete *bars[i]->front();
pop_front();
}
delete bars[i];
}
delete[] bars;
With regard to your update, I would then suggest changing the type of bars to:
vector<Bar*>* bars;
and the allocation to (without the need to do the for loop allocation suggested above):
bars = new vector<Bar*>[10];