Creating n objects of class

Hi, I'm rather new to C++ programming and I've ran into a problem.

In the following the user is promted to enter the number of enemies he is to face.
I now need to create enemy objects equal to the user input, but my original idea doesn't work.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

//game variables
unsigned int nTraps;
unsigned int nEnemies;
const string enemyName [] = { "enemy01", "enemy02", "enemy03", "enemy04", "enemy05", "enemy06", "enemy07", "enemy08", "enemy09", "enemy10"};

//some functions and classes excluded at the moment
void seedRandom () {
    srand((unsigned)time(0));
}

class Enemy
{
    public:
        Enemy(string n);
        ~Enemy();
        void showStats ();
    protected:
        int coordX;
        int coordY;
        int health;
        int attack;
        int defence;
        int damage;
        string name;
};

Enemy::Enemy(string n) {
    health=90+(rand()%21);
    attack=10+(rand()%5);
    defence=10+(rand()%5);
    damage=10;
    name=n;
}

Enemy::~Enemy() {}

void Enemy::showStats() {
    cout<<"Health is: "<<health;
    cout<<"\nAttack is: "<<attack;
    cout<<"\nDefence is: "<<defence;
    cout<<"\nDamage is: "<<damage;
    cout<<"\nName is: "<<name<<endl;
}

int main ()
{
    seedRandom();

    unsigned int userInput = 0;
    bool enemiesSet = false;
    do {
        cout<<endl<<"Please enter number of enemies (min. 3, max. 10)";
        cin>>userInput;
        if (userInput<3 or userInput>10) { cout<<"Bad input!"; }
        else {
            nEnemies = userInput;
            enemiesSet = true;
        }
    } while (!enemiesSet);

    for (unsigned int x=0; x<nEnemies; x++) {
        Enemy enemyName[x] (enemyName[x]); //Enemy constructor looks like this: Enemy(string n);
        enemyName[x].showStats();
    }
}


I'm getting this compile error (using code::blocks):
error: variable-sized object 'enemyName' may not be initialized
c::b states the compile error is in line 68.

Any good suggestions on how to name the objects would be highly appreciated.
You're not really using the whole [x] notation right there.

A problem I can see is that your Enemy objects will only be declared locally within the for loop and will then be destroyed when it finishes. Perhaps create a vector of pointers to enemies and store them in there.

1
2
3
4
5
6
7
std::vector<Enemy*> enemies;

for (unsigned int x=0; x<nEnemies; x++) {
        Enemy *enemy = new Enemy(enemyName[x]);
        enemies.push_back(enemy);
        enemy->showStats();
    }
Last edited on
Thanks Muckle ewe, your suggestion is perhaps a bit beyond my skill, but I think I understand what it does ... and it works fine.

I'm working on how to access the objects now, from different points. I think I have it figured out. If it works I'll post it a bit later.
Turns out it was pratically the same as the initializing the objects
1
2
3
4
for (unsigned int x=0; x<nEnemies; x++) {
        Enemy *enemy;
        enemy = enemies[x];
        enemy-> moveEnemy();


Thanks again for the help, and 'forcing' me to better understand pointers.
closed account (zb0S216C)
The correct way to use a std::vector in this case is:

1
2
3
std::vector<Enemy> Enemies;
//...
Enemies.push_back(Enemy());

To create an array at run-time, you'll have to do some manual labour; that is, DMA (Dynamic Memory Allocation). For you, you'll need something like this:

1
2
3
4
5
int RequestedNoOfEnemies(5);
Enemy *ArrayOfEnemies(new Enemy[RequestedNoOfEnemies]);

//...
delete [] ArrayOfEnemies;

Wazzak
Let me see if I get this.

Instead of pointing at the class objects, you assign them to a vector of class objects?
Is it possible to access the objects simply using Enemy[x].classfunction?


No offense, but I can't figure out what I need the last part for.
Last edited on
Yea, if Enemy is an array of some objects that have the classfunction that's exactly what you do. Note that pushing the objects (not pointers) into the vector is better (for this program), then you don't need to delete the pointers later.
[mr.burns]Excellent[/mr.burns]
closed account (zb0S216C)
AbR wrote:
"Instead of pointing at the class objects, you assign them to a vector of class objects?"

Yes, as Mathhead200 said. Internally, the std::vector allocates 1 big chunk of memory where it will store its objects in a consecutive manner.

AbR wrote:
"Is it possible to access the objects simply using Enemy[x].classfunction?"

That's one way, but it's no safe. The safe way to access a std::vector is through std::vector::at(): A function that validates the given offset. If the offset exceeds the number of objects in the vector, it'll throw an exception. However, the sub-script operator ([]) doesn't perform these checks; thus, allows you to write past the last object.

AbR wrote:
"No offense, but I can't figure out what I need the last part for."

It creates an array dynamically. Commonly used to create an array, whose length is determined at run-time, which cannot be done with static arrays. Consider it a less superior alternative to the std::vector.

Wazzak
Last edited on
std::vector::at(): vs Enemy[x].classfunction

Point taken.

It creates an array dynamically. Commonly used to create an array, whose length is determined at run-time, which cannot be done with static arrays. Consider it a less superior alternative to the std::vector.

Lucky punch - this is exactly what I need to create the game map based on user input during runtime.
Last edited on
Lucky punch - this is exactly what I need to create the game map based on user input during runtime.

Hmn, I don't think I can point to a two dimensional array of chars allocated during runtime. I can't even create the 2D array with new?
closed account (zb0S216C)
AbR wrote:
"I can't even create the 2D array with new?"

You can. Such an allocation has 2 parts. For my example, I'll allocate a 10x10 array.

1
2
3
4
5
6
7
8
9
10
// Symbolic Metaphors:
const int ROW_QUANT(10);
const int COL_QUANT(10);

// Part 1:
int **Map(new int*[ROW_QUANT]);

// Part 2:
for(int I(0); I < ROW_QUANT; ++I)
    Map[I] = new int[COL_QUANT];

Part 1 allocates an array of pointers to ints. In part 2, each pointer allocated in part 1 is assigned an array of 10 ints.

Or! you could do something less readable (when accessing), but more efficient in the long run:

 
int *Map(new int[(ROW_QUANT * COL_QUANT)]);

Wazzak
Last edited on
@Framework
Thanks for the input, but this is beyond my skills at the moment.

I have work-around-method that I'll use, and then focus on the classes, which was my primary goal for writing this small game, which now also includes a vector of objets. If I top it with more code I'm unfamiliar with, I might get lost in my own code :-)

I'll keep a link to your example for when I get a better understanding of it.

---

A separate question regarding the vector of objects:
Let say that vector Enemies holds 4 object of type Enemy like this:
Enemies[0] = enemy01
Enemies[1] = enemy02
Enemies[2] = enemy03
Enemies[3] = enemy04

... and enemy02 is killed by the player. I was thinking I should destroy the object with the destructor (~Enemies.at(1)).
After the object is gone, is Enemies.at(1) now empty or will it hold enemy03 (and Enemies.at(2) holding enemy04) or will I need to use Enemies.erase(1) to remove the empty space?
closed account (zb0S216C)
AbR wrote:
"I was thinking I should destroy the object with the destructor "

Never call the destructor unless you're using placement new. You can call it, but the std::vector would invoke it again which leads to erratic behaviour.

When you erase an object from a std::vector, all objects on the right-hand side are moved 1 place to the left; thus fill the gap.

Wazzak
The objects are created with a basic constructor and pushed on to a vector - based on your suggestion above:
1
2
3
4
5
6
7
8
9
10
11
vector<Enemy> Enemies;

//spawns enemies
void spawnEnemies () {
    /..

    for (int x=0; x<nEnemies; x++) {
        cout<<"Enemy "<<x+1<<endl;
        Enemies.push_back(Enemy());    
   }
}


So the objects are not created with new.

After erasing an object from the vector, will the object still reside in memory? But with no way to get to it?
closed account (zb0S216C)
AbR wrote:
"After erasing an object from the vector, will the object still reside in memory?"

No. The compiler will invoke the destructor which invalidates the object.

Wazzak
Couldn't be much easier.
Topic archived. No new replies allowed.