0

So, a quick summary of why I'm trying to do this:

I'm making a space flight program, wherein (once I code in more than one ship) I will be able to store different ships, e.g. craft[HAB], craft[AYSE], craft[ISS], and so forth. At the moment, I have only coded in one ship, and I declare it like so:

enum craft {HAB, CRAFTMAX};
...
[declaring ship class here]
...
ship craft[CRAFTMAX];

However, not all ships will be the same structure. For example, HAB (short for Habitat) will be a circle with three engine pods on the bottom, AYSE will be a space station with a tube going to the centre, and docking lights, and so forth. I am making these functions draw a vector to the screen.

At the moment, I have declared ship::draw, and I just use this to draw the Hab. However, I want to be able to modify each draw function to draw that ship, i.e. craft[AYSE].draw() will have a different declaration than craft[HAB].draw().

I've thought, and looked up different ways to do this, but I haven't gotten much success. I'd still like to be able to iterate through all the crafts for ease of calculating gravity and collisions. But I'm guessing if it's impossible to individually declare functions when they are elements of an array, it won't be too much trouble to declare each ship individually, as there will only be 10, max.

Here is my git repository that is storing this, if you want to take a look at any other code. It is definitely a bit unorganized, as it is a monopoly project, and I only ever see myself using it.

Any of you tried to do this? I'm sure there must be a few people out there!

And thanks in advance.

pmelanson
  • 330
  • 4
  • 16

4 Answers4

3

I think you will be much better by using a base class for a Ship object, then deriving from this base class for the different types of ships. Then use some container that allows you to iterate through all ship objects and call the respective functions. Like:

class Ship {
public:
  virtual void draw() const = 0;
};

class HAB : public Ship {
  virtual void draw() const;
};

class AYSE : public Ship {
  virtual void draw() const;
};

Then using a container like:

vector<Ship> ships;
ship.insert(HAB());
ship.insert(AYSE());

// to draw
for_each(ships.begin(), ships.end(), mem_fn(&Ship::draw));

I came up with this fairly quick so you will have to work out the details. The way you are thinking of doing it is not very OO and will have problems in terms of maintenance (think Single Point of Maintenance).

keelerjr12
  • 1,693
  • 2
  • 19
  • 35
  • I'll still be using an array instead of a vector, because I won't be changing the amount of ships, but I'll look up that last line, that looks interesting Also, hadn't even thought of inheriting each craft from ship class, good idea! – pmelanson Apr 15 '12 at 02:15
  • An array will work, but a vector will be able to perform the memory management for you. Once the vector goes out of scope all Ship objects will be destroyed. The last lime is just an algorithm instead of the normal for(int ... i++). Try to use algorithms over explicit loops. – keelerjr12 Apr 15 '12 at 02:23
  • When you say try to use algorithms over explicit loops, do you mean that instead of, say, calculating the gravitational attraction between all objects with a loop, I should just make one function that calculates the gravitational attraction of everything? – pmelanson Apr 15 '12 at 02:28
  • 1
    Scott Meyers can do a better job explaining it than I can: http://www.drdobbs.com/184401446 – keelerjr12 Apr 15 '12 at 02:31
  • Wow, this definitely looks cool, I'll be reading this for sure. Thanks again. EDIT: Welp, he just answered questions that I had while learning to program, and told me how to get even more efficiency out of it. I like this guy. – pmelanson Apr 15 '12 at 02:37
0

I don't like the look of your code - using the word craft as both a type identifier and a variable identifier...

But from your question it looks like you want to use inheritance. So you declare a

class ship {
    // put here all methods that all ships have and that are the same
    // and all data that all ships.
    virtual void Draw( ) = 0; // subclasses of ship are forced to implement their own Draw
    // etc.
    };

Now when you want an array of ships, make it an array of pointers to ship. You can then put in pointers to the subclasses, and use dynamic_cast to get pointers back to the subclasses when you need them. But by calling A[4]->Draw() you will get whatever Draw routine is appropriate for the object in location 4 of the array.

DRVic
  • 2,481
  • 1
  • 15
  • 22
  • I'll change the enum identifier, but I never use the enum identifier anywhere else anyways. But I agree, good coding practice, will change. – pmelanson Apr 15 '12 at 02:19
0

You'll probably want to declare a base class and implement each type of ship as child classes.

class HAB: public ship{
  //code here
};

For more information on inheritance: see this tutorial.

The colon shows that HAB inherits member data and function from the class ship. This way you can define some functions uniquely in each of the child classes while still having them share important functions with the base class. For example each ship type is likely to have similar member functions like get_position() whereas a draw function depends specifically on each ship type.

The beauty of polymorphism is that you can refer to the child classes as their parent class. So you can make an array of ship * (ship pointers) to refer to an array of child classes.

ship * array[CRAFTMAX];
array[0]=new HAB;

However before using this sort of thing you should be really up on your pointers because mismanagement can result in memory leaks. That is, you allocate memory and never free it up.

This website has some nice instruction in polymorphism.

Cerin
  • 63
  • 10
0

The OO way would be to create a hierarchy of types, with each type representing one of the types of aircrafts. Use virtual functions to provide different implementations for the common interface (declared in the base class).

Once you have this, you will need to store the objects in the container polymorphically (i.e. not the object, but rather a smart pointer to the objects). The (smart) pointers would be of the base type and the objects of the actual types. I would recommend that you use a higher level container rather than arrays (i.e. std::vector<std::unique_ptr<ship>>)

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489