Click here to Skip to main content
15,917,329 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
so im trying to make a class have another class as a data member only I do not know the type of class that this data member will be. example:

I left out a lot of obvious code for readability.

class weapon
{
    public:
      string gettype()
      {
       return type;
       }
    private:
      string type;

};

class sword : weapon
{
   public:

   private:
     string type = "sword";

};

class knife : weapon
{
   public:
   private:
     string type = "knife";
};

class unit
{
  public:
    void setequippedweapon( how_do_i_do_this  )  // attempting to assign a unknown class as a data member?
    {
     equippedweapon = how_do_i_do_this;
     }
  private:
    how_do_i_do_this equippedweapon;  // attempting to declare the unknown class data member?
}

int main()
{
  unit soldier;
  weapon myknife;
  weapon mysword; // i will send one of these to be equipped
  soldier.setequippedweapon(how_do_i_do_this);   // since this could be a knife, sword, or whatever other weapon class i make in the future, how do i declare and use this?
  cout << "soldiers weapon is a: " << soldier.equippedweapon.gettype(); // and how to access the weapon's member functions/variables through the soldier?
  return 0;
}
Posted
Updated 18-Aug-10 19:07pm
v3

void setequippedweapon( how_do_i_do_this  )


can simply be replace by

void setequippedweapon( weapon  w )
{
    equippedweapon = w;
}
private:
weapon equippedweapon;


then use it like

soldier.setequippedweapon(knife);


This works because all weapon classes derive from the same base class, weapon. The you make use of polymorphism to use the actual attributes of that particular weapon.
 
Share this answer
 
You can operate with the base class pointers in your unit class :) :

class CWeapon
{
protected:
  CString m_cszType;

public:
  CWeapon() { m_cszType = _T("yet empty"); }

  const CString& GetType() { return m_cszType; }

  // optional, important for the instances assignments
  const CWeapon& operator = (const CWeapon& other) {
    m_cszType = other.m_cszType;
    return *this;
  }
};

class CSword : public CWeapon
{
public:
  CSword() { m_cszType = _T("sword"); }
};

class CSword : public CWeapon
{
public:
  CKnife() { m_cszType = _T("knife"); }
};

class CUnit
{
  CWeapon* m_pcWeapon;
  bool m_bWeaponOwner;

public:
  CUnit() {
    m_pcWeapon = NULL;
    m_bWeaponOwner = false;
  }
  
  ~CUnit() {
    if (m_bWeaponOwner && m_pcWeapon) {
      delete m_pcWeapon;
    }
  }

  CWeapon* GetWeapon() { return m_pcWeapon; }

  bool SetWeapon(CWeapon* pcWeapon, bool bOwner = true) {
    bool bResult = (NULL != pcWeapon);
    if (bResult) {
      if (m_bOwner && m_pcWeapon) {
        delete m_pcWeapon; // old
        m_pcWeapon = NULL;
      }
      m_bOwner = bOwner;
      m_pcWeapon = pcWeapon; // new
    }
    return bResult;
  }
};

int main()
{
  CUnit aSoldier;
  CKnife aKnife;
  
  aSoldier.SetWeapon(&aKnife, false); // the knife does not die with the soldier
  ASSERT(aSoldier.GetWeapon()->GetType() == _T("knife"));

  aSoldier.SetWeapon(new CSword(), true); // the sword dies with the soldier
  ASSERT(aSoldier.GetWeapon()->GetType() == _T("sword"));
  
  return 0;
}


...but it is not the theoretical polymorphism yet, I think :)
 
Share this answer
 
v2
How about something like (I'll just modify your code a little bit, but I'm not saying that this is the best way to go, personally I would organize things different):
class weapon
{
public:
    weapon() : type("unknown") {}
    explicit weapon(const string& t) : type(t) {}
    virtual ~weapon() {}

    string gettype() const
    {
       return type;
    }
      
private:
    string type;
};

class sword : public weapon
{
public:
    sword() : weapon("sword");

    // Here you can add specific things to sword...
};

class knife : public weapon
{
public:
    knife() : weapon("knife");

   // Here you can add specific things to knife...
};

class unit
{
public:
    void setequippedweapon(const weapon* w)
    {
        equippedweapon = w;
    }
    
    weapon* getequippedweapon() const
    {
        return equippedweapon;
    }

private:
    weapon* equippedweapon;
}

int main()
{
    unit soldier;
    knife myknife;
    sword mysword; // i will send one of these to be equipped
  
    soldier.setequippedweapon(&mysword);
    cout << "soldiers weapon is a: " << soldier.getequippedweapon()->gettype();
    return 0;
}


I hope that this will give you an idea on how the things can be done. But IMO you should pick up a good programming book and learn basic concepts. You could also use resources from Internet but a good book would be more useful.

Happy coding! :)
 
Share this answer
 
v2
Comments
Eugen Podsypalnikov 19-Aug-10 2:46am    
Reason for my vote of 5
A precise answer :)
Nuri Ismail 19-Aug-10 2:52am    
Thank you Eugen! :)
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:
      // Add constructors to taste...

          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
 
Share this answer
 
v2
Comments
Niklas L 19-Aug-10 17:17pm    
Thanks for pointing out the object slicing problem.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900