简体   繁体   中英

How to loop through class objects in C++

My question is How can I have combat for all enemies by having only 1 function?

At the moment I create my enemies by writing Enemy (class) and giving it object + number name, then I just give some inputs and it looks like:

Enemy object1(1, 20, '/', "AQUA", 1);
Enemy object2(5, 40, '/', "YELLOW", 2);
Enemy object3(10, 60, '/', "WHITE", 3);

Then I have a runtime for Combat and I run an awful while loop:

while (object1.getHp() > 0)

to run my combat code.

So now I need to have just one combat function to run all different enemies, I already tried a lot of thing but nothing seems to work. Any idea on what can I do?

Sounds and looks dumb but I really can't guess anything to do about it, already lost tons of hours looking for a solution.

What you need first is a container able to hold your Enemy instances or pointers to them. Most containers are templated classes, which have to be typed. One of them is the vector (a contiguous 'list'), which can be created in your case as

  • std::vector<Enemy> : A 'list' holding your full objects
  • std::vector<Enemy*> : A 'list' holding pointers to your objects

An example if you take references from your objects:

std::vector<Enemy*> enemies;
enemies.push_back(&object1);
enemies.push_back(&object2);
enemies.push_back(&object3);

If you are not familiar with pointers, you can look here , even though it may be a bit opaque at first!

Looping

A range for loop will let you iterate over your container pretty easily

for ( auto enemy : enemies ) {
    enemy->doStuff();
}

The auto will deduce the type from the container, and doStuff will be executed sequentially for every enemy in your list. If your container contains instances instead of pointers * , you will need to take a reference & of the object instead, and use for ( auto& enemy : enemies ) . This will ensure your object is modified in place, and not copied, otherwise, your changes won't get reflected in the container.

Memory management

As mentioned in other answers, when you are ready to move to the next level, you can have a look at smart pointers . Because C++ code is unmanaged and has no out-of-the-box memory management, you are responsible for delete ing any new ed object. Smart pointers will help you more safely manage the lifespan of your data. Raw pointers (without any smart pointer to protect them) are considered bad practice in most situations nowadays.

However, your Enemy instances are created on the stack, so they will get automatically destroyed at the end of their scope (function, {} , ...). This also means that if you have any pointer * or references to them that you use outside this scope, your object has been destroyed already, and you will encounter a memory exception or undefined behavior, ie Don't do that!

You can use std::vector to group your objects like this:

std::vector<Enemy> vEnemies
{
    { 1,  20, '/', "AQUA",   1 },
    { 5,  40, '/', "YELLOW", 2 },
    { 10, 60, '/', "WHITE",  3 }
};

And, then you can use C++11's range-for loop for all the objects:

for ( auto& e : vEnemies )
{
    e.doSomething();
}

You may also explore std::for_each for your other use-cases.


If you're looking for a solution with pointers eg std::vector<Enemy*> then you ought to first look at smart pointers ( std::unique_ptr / std::shared_ptr along with std::make_unique / std::make_shared ) to enforce RAII for your objects allocated on the heap / free-store.

Please find the rough instructions below to solve your problem.

  • Store all objects inside an array or advanced structures like vector.
  • Set a flag to indicate if there is at least one enemy alive
  • Run a while loop as long as flag remains true
    • set flag to false
    • For each object in array,
    • Check if health point more than zero
      • Then perform your action
      • set flat to true

That's all.

Define a container of enemies preferably a std::vector<Enemy> and iterate over all the objects in the container.

std::vector<Enemy> enemies;
// Now construct your enemies in the vector.
enemies.emplace_back(1, 20, '/', "AQUA", 1);
enemies.emplace_back(1, 20, '/', "YELLOW", 2);
.
.
// Now loop through.
for (auto & enemy: enemies) {
  enemy.Combat(); // Whatever you want
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM