0

In C++, how can I declare an interface s.t. I can use it as shown below:

/** Enemy "Interface" */
Class Enemy {
    Enemy();
    virtual ~Enemy();
    virtual void doStuff() = 0;
};

/** Enemy of type 1 */
Class Enemy_type1 : public Enemy {
    Enemy_type1();
    virtual ~Enemy_type1();
    virtual void doStuff() {
        // different for every type of enemy
    }
};

/** Add an enemy to EnemyManager */
void EnemyManager::addEnemy(Enemy * e) {
    this->enemies.push_back(*e); // declared as vector<Enemy> enemies;
}
Ben
  • 15,938
  • 19
  • 92
  • 138
  • 1
    @see http://stackoverflow.com/questions/318064/how-do-you-declare-an-interface-in-c – Nicola Coretti Oct 18 '11 at 14:41
  • @Kerrek SB I added the `: public Enemy` and changed the "c". Thank you for the reminder, I will accept answers once I get to it since I'm often working on multiple problems at a time. – Ben Oct 18 '11 at 14:42
  • @Nicoretti I don't see how that solves my problem as it doesn't says how I can refer to the "interface" (see my addEnemy function). – Ben Oct 18 '11 at 14:44

2 Answers2

5

First, you'll have to (or at least want to) make the functions that make up your interface public:

class Enemy {
public:
    Enemy();
    virtual ~Enemy();
    virtual void doStuff() = 0;
};

Then you'll inherit from it (C++ doesn't have "interfaces" and "classes" as separate concepts).

class Emeny_type1 : public Enemy { 
    // ...
};

Finally, since these are polymorphic types, you'll want to create a collection of pointers to enemies, not of actual Enemy objects:

void EnemyManager::addEnemy(Enemy const *e) { 
    enemies.push_back(e);
}

This does raise the issues of object lifetime and ownership (which mostly aren't issues in Java). When you add an item to the collection, you'll need to ensure that it's not destroyed as long as you're going to use it, and is destroyed once you're done with it (e.g., when an enemy has been defeated, you might want to remove it). You need to decide whether the EnemyManager is going to delete enemies that are no longer needed, or some other code. If the EnemyManager is going to delete them, you may need (or want) to add a clone function to your Enemy interface for it to get a copy of the object being added to the collection.

Edit: based on your comment, you're not quite sure how to use the Enemy "interface" of a pointer you've stored in your collection. Fortunately, that's fairly simple, something like this:

for (int i=0; i<enemies.size(); i++)
    enemies[i]->doStuff();
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • I read that question 4 times before I saw that he was storing `Enemy`s by value. – deft_code Oct 18 '11 at 14:49
  • Ohhh... I have to write `vector enemies;`. See, what I kept trying was `vector *enemies;` – Ben Oct 18 '11 at 15:19
  • You don't want (and can't have) a `vector` -- it needs to be `vector` (and, as show in the sample code above, you want to push a `e`, not `*e`. – Jerry Coffin Oct 18 '11 at 15:20
  • There's also `vector >` to consider. It isn't a perfect solution, but it handles a lot of memory management. – David Thornley Oct 18 '11 at 15:32
  • @DavidThornley: Quite true -- I debated mentioning that, but for the moment decided against it. For that matter, it could be any number of smart pointer types, not just shared_ptr. – Jerry Coffin Oct 18 '11 at 15:41
0
/* Enemy Interface (Abstract Base Class)
   This goes in a header, say Enemy.hpp
 */
class Enemy {
public: // note default access is private in classes
    Enemy();
    virtual ~Enemy();
    virtual void doStuff() = 0;
};

/* Add an enemy to EnemyManager.
   The interface is a type, and is known!
   It doesn't need to know anything about the subclasses
   which implement the interface.
 */
void EnemyManager::addEnemy(Enemy * e) {
    this->enemies.push_back(*e); // vector of Enemy POINTERS
}

/* Enemy of type 1.
   This would go in say Enemy1.hpp - it depends on Enemy.hpp,
   but EnemyManager doesn't need to know anything about this.
 */
Class Enemy_type1: public Enemy {
public:
    Enemy_type1();
    virtual ~Enemy_type1();
    virtual void doStuff();
};

/* ... and in a .cpp file somewhere ... */
Enemy_type1::Enemy_type1() : Enemy()
{
   // this is redundant unless you have some work for it to do
}

Enemy_type1::~Enemy_type1()
{
}

void Enemy_type1::doStuff()
{
  // do your stuff here
}
Useless
  • 64,155
  • 6
  • 88
  • 132