While all the answers here will do the job, consider avoiding using implementation inheritance. Implementation inheritance can have all sorts of "interesting" side effects (for example Niklas solution would suffer from object slicing, Eugen's has all sorts of problems with exception safety and baroque object ownership) which you can largely avoid if you make weapon an interface class:
class weapon
{
public:
virtual std::string name() const = 0;
};
then when you override for the particular classes:
class sword : public weapon
{
public:
virtual std::string name() const
{
return "sword";
}
};
class plasma_rifle : public weapon
{
public:
virtual std::string name() const
{
return "Plasma rifle with a 40kw range";
}
};
There are some added bonuses to this including no data members. Woo hoo! You can copy and assign this lot all day long without having to implement loads of boiler plate guff.
Secondly you can unit test your code a lot more easily. You can introduce objects just for testing:
class test_weapon : public weapon
{
public:
virtual std::string name() const
{
return "I'm a test chopper!";
}
};
and use those in your test cases for unit without having to wonder when a test fails if it's a change to unit or weapon that's causing the problem.
Anyway, the point to this lot is make your concrete classes depend on interface classes. Your code will end a bit cleaner for it. As an example let's add a damage operation to your weapons...
class damage_effect
{
public:
virtual ~damage_effect() {}
virtual unsigned hit_points_inflicted() const = 0;
};
class linear_damage_effect : public damage_effect
{
public:
linear_damage_effect( unsigned minimum_damage, unsigned maximum_damage )
: minimum_( minimum_damage ), maximum_( maximum_damage )
{
}
virtual unsigned hit_points_inflicted() const
{
return minimum_ + std::rand() % ( maximum_ - minimum_ );
}
};
class weapon
{
public:
virtual std::string name() const = 0;
virtual std::auto_ptr<damage_effect> damage_inflicted() const = 0;
};
class sword : public weapon
{
public:
virtual std::string name() const
{
return "sword";
}
virtual damage_effect damage_inflicted() const
{
return std::auto_ptr<damage_effect>(
new linear_damage_effect( 1, 8 ) );
}
};
This probably all looks a bit bewildering, but doing this means that your client code, the thing that's pitting your units against each other only has to worry about weapons and damage_effects, it doesn't have to know anything about the details of either. So...
class unit
{
public:
void take_damage( const std::auto_ptr<damage_effect> &effect )
{
hit_points_ -= effect.hit_points_inflicted();
}
void attack( unit &attacked )
{
attacked.take_damage( w_->damage_inflicted() );
}
private:
int hit_points_;
weapon *w_;
};
If you look at the two member functions I've shown the implementation of you'll notice that everything's abstract. It doesn't matter what the weapon the unit is using neither unit class needs to know. It might be the geek in me but when I see that I think "yep, that works for me."
Anyway, this is turning into a way too long post so I'll stop there. The important things are...
- Only use interfaces in class interfaces. (i.e. don't have functions returning linear_damage_effects, have them return damage_effects)
- Only have concrete classes use interfaces EXCEPT for objects they create. So classes implementing weapon can create specific damage_types when they inflict their damage
Cheers,
Ash
Corrected an incorrect indirection