I am working on a game project, and my teammate has a certain way of solving our reference issues, and it works great, except, when the game is big, we will end up with massive constructors.
class Player
{
private:
Weapon *w1, *w2, *w3;
Armor *a1, *a2;
public:
Player(Weapon *w1, Weapon *w2, ...) : w1(w1), w2(w2), ...;
}
Then my constructor is Player(w1, w2, w3, ...); which is disturbing, what if the player class had 100 references?
Is there a way to make this syntax simpler, or are we doing it wrong? Is there a better way of making references to variables which are outside the player class?
IMPORTANT
The above is purely an example, a poorly written one. I don't just have weapons and armors. I have a ton of classes. I have a developer console reference, I have armor references, items, I have references to the debugging class, the logger class, and the list goes on. A vector is not helpful for me. Sorry for the poor example.
Why not use vectors ?
std::vector<Weapon *> W;
std::vector<Armor *> A;
You can indeed put it all in a single vector, if you use inheritance.
For a fantasy-themed game (which I assume you're writing) it could be something like this:
// The base object, contains common attributes
class Object { ... };
// The item class
class Item : public Object { ... };
class Weapon : public Item { ... };
class Sword : public Weapon { ... };
class Clothing : public Item { ... }
class Armour : public Clothing { ... };
Then it's enough with one vector for all equipment:
std::vector<std::shared_ptr<Item>> inventory;
For worn stuff, you could have separate variables, like
std::shared_ptr<Weapon> wielded;
std::shared_ptr<Clothing> head; // Helmets, hats, etc.
Or use a map for the equipped stuff:
std::unordered_map<std::string, std::shared_ptr<Item>> equipped;
Then you can use e.g.
equipped["wielded"]
to get the wielded item.
For completeness, some other possible classes in the class tree above might be:
class Character : public Object { ... }
class Player : public Character { ... }
class Monster : public Character { ... }
class Dragon : public Monster { ... }
class RedDragon : public Dragon { ... }
class TheUltimateBossDragon : public RedDragon { ... }
As a side note, I have used hierarchies like the above in my own games previously. However in my next game (when and if I get that far) I will probably use another pattern, where classes indicates behavior. For example, a sword is equipable, it's a damage_inflicter, it's takeable, etc. This means more complex inheritance hierarchies, with much more multiple inheritance, and will probably use RTTI more. But on the bright side it will hopefully be more flexible.
Rather than having a fixed number of pointers to a small number of types, try using vectors:
class Player
{
private:
std::vector<Weapon*> weapons;
std::vector<Armor*> armors;
public:
Player(const std::vector<Weapon*>&, const std::vector<Armor*>&);
}
Related
I've got a base class calls:
class item
{
public:
item();
virtual string act()=0;
};
and a few classes that inherit from this one;
class food:item
{
public:
food();
string act();
};
class ant:item
{
public:
ant(unsigned int new_ant);
~ant();
string act();
};
class anthill:item
{
public:
anthill();
string act();
}
then I've got a list that serves as a container of several instances of those classes.
I iterate through the list.
Now I've to use different functions depending on the type of the instance that are hidden behind the Iterator.
but I can't find a way to distinguish between e.g. an ant and food
I've tried comparisons with typeinfo
as well as
ant* test = dynamic_cast<ant *>((*i)); // returns nullptr even though debug says i is an ant
ant* test = dynamic_cast<ant *>((*i)); // returns nullptr even though debug says i is an ant
That's because your classes use private inheritance. Change them to use public inheritance.
Use
// |
// v
class food : public item
{
public:
food();
string act();
};
I have done this by using containers of type_info hash codes to function pointers, For example a language interpreter implemented operator resolution by having maps like the following:
std::unordered_map<std::pair<size_t, size_t>, add_func*>fnsAdd = boost::assign::map_list_of
(std::make_pair(typeid(integer_value).hash_code(), typeid(integer_value).hash_code()), (add_func*)&integer_value_integer_value_Add)
(std::make_pair(typeid(integer_value).hash_code(), typeid(real_value).hash_code()), (add_func*)&integer_value_real_value_Add)
I'm trying to create a way to hold all entities in my C++ game, arrays wouldn't work since they are limited to one type. I need to store anything with the class Entity, and all it's derivatives in it. I've been trying all day to get a way to store all game entities in a way I can just loop through them all and draw them. Still haven't found a solution.
Assuming Entity is some base class that many things derive from, you can have a container (any container is fine, but std::vector is a good place to start unless you have some other specific requirements).
class Entity
{
public:
virtual void Draw() = 0;
};
class Atom : public Entity
{
public:
void Draw() override {}
};
class Environment : public Entity
{
public:
void Draw() override {}
};
int main()
{
std::vector< std::shared_ptr<Entity> > entities;
entities.push_back(std::make_shared<Atom>());
entities.push_back(std::make_shared<Environment>());
// Draw entities:
for (size_t ent = 0; ent < entities.size(); ++ent)
{
entities[ent]->Draw();
}
return 0;
}
You might be able to use std::vector. It has a lot of built-in functions for simple data manipulation, and you can use it with any type.
I have base class Item which store some data and grant access to it by accessors, like:
class Item{
(...)
public:
int get_value();
double get_weight();
ItemMaterial get_material();
(...)
}
Then I've got derived classes like Weapon, Armor which add some additional data:
class Weapon : public Item {
(...)
public:
int get_dmg();
(...)
}
I store these Items in some container:
std::vector<Item*> inventory;
And here comes the problem with interface - how to get access to derived class data? I was thinking, and got 3 ideas:
1. Separate interfaces
Each derived class adds its data, like it is shown above, and then use dynamic_cast:
Item *item = new Weapon;
int dmg = dynamic_cast<Weapon*>(item)->get_dmg();
2. Common interface class
Make an interface class with all accessors:
ItemInterface{
public:
virtual int get_value() = 0; //Item interface
virtual double get_weight() = 0;
(..)
virtual int get_dmg() = 0; //Weapon interface
(...)
}
And then something like this:
Item : public ItemInterface{ (...) }
and
Weapon : public Item { (...) }
and finally we can access the data:
Item *item = new Weapon;
int dmg = item->get_dmg();
3. Combination with templates and enums
This idea is maybe a little weird :-) but:
implement enum with all item data:
enum class ItemData{
Value,
Weight,
Material, //Item data
(...)
Damage, //Weapon data
(...)
Defense, //armor data etc.
(...)
Null
}
and in base class some template function like this:
template<typename T>
T get_data(ItemData data){
switch(data){
case ItemData::Value: return _value; break;
case ItemData::Damage: return _dmg; break;
(...)
}
}
and access data like:
Item *item = new Weapon;
ind dmg = item->get_data<int>(ItemData::Damage);
===
How do you think it should be done? I will be grateful for any advices!
Regards.
Your second and third option is obviously not the way to go - whenever you add a new type of item, you will also have to change the base class or the enum - that is definitely not what you want to if you need any basic form of maintainability in your code.
And here comes the problem with interface - how to get access to derived class data
First you have to think of "where will your code do this"? Most of your code dealing with the whole inventory should only use the content as Item*, using only functions from the Item class.
If you have code specificially dealing with Weapon objects, the place where the Weapon objects are created (and inserted into the inventory), may also add them to another variable, maybe a weapons list in form of a
std::vector<Weapon*> weapons;
or to a member variable Weapon* of a class Warrior or something like that (but beware, you now will have two pointers to the same objects, so you have to think about ownership). So the code dealing only with weapons (for example, a member function of Warrior) does not access the inventory to get a Weapon object, it will always use the Weapon* directly.
If, for some reasons, you have to write some code which does something for all weapons from your inventory, then write a single function which extracts all Weapon objects using the dynamic_cast (or even better: make it an iterator function), and reuse this function whenever you need to get access to all weapons. So you don't clutter your code all over with dynamic casts, but keep this in just one place.
EDIT: another alternative (avoiding the dynmic cast) is using the visitor pattern, see this post. But I don't really like the answer of that post, in the presented form it will imply a cyclic dependency "Base -> Visitor -> Derived -> Base", which is IMHO a bad design.
ValueType Weapon::getProprtyValue( PropertyType id ) {
switch( id ) {
case kWeaponProperty01: return m_weaponProperty01;
...
default: return Item::getPropertyValue( id );
}
}
You can make some kind of universal accessor method, though it have some limitations, it could be quite handy, especially in case of content editors, serialization etc.
I asked a couple days ago some clarifications on inheritance, a concept I am still trying to understand. Here is the follow up question, since I am still facing problems.
In my project I have 2 types of objects, Hand and Face, both inheriting from the base class BodyPart. BodyPart is something like this:
class BodyPart
{
public:
typedef boost::shared_ptr<BodyPart> BodyPartPtr;
BodyPart();
virtual ~BodyPart();
private:
int commonMember1;
double commonMember2;
public:
int commonMethod1();
int CommonMethod2();
}
while Hand is something like this:
class Hand : public BodyPart
{
public:
Hand();
~Hand();
private:
int numFingers;
double otherVar;
public:
int getNumFingers();
void printInfo();
}
I also have a vector of BodyPart elements
std::vector<BodyPart::BodyPartPtr> cBodyParts;
composed of Hand or Head objects. In the previous question I was told that this approach makes sense, I just had to cast from the base class to the derived using boost static_pointer_cast
Now, the problem now is that for some of the objects in the vector I don't know whether they are Hand or Head, so at some point in my code I can have in cBodyParts some Hand elements, some Head elements as well as some BodyPart elements. After some further analysis I am able to correctly classify the latter as either Hand or Head and modify accordingly the elements in the vector, but I have no idea on how to make it. Shall I just delete the case class element and create a derived one with the same property? Shall I just avoid inheritance in case like this?
Thanks in advance for the help
EDIT: I have augmented the examples to make them clearer.
Relaying on casts is usually a sign of a bad design. Casts have their place, but this does not look to be it.
You need to ask yourself what do you want to do with the objects stored in cBodyParts. For sure, you will be doing different things with a Hand or with a Head, but you can probably abstract them somehow: this is what virtual functions do. So, in addition to what you have already written for your classes, you would just need an additional virtual function in them:
class BodyPart
{
// Same as you wrote, plus:
public:
virtual void InitialisePart() = 0; // Pure virtual: each body part must say how to process itself
virtual void CalibrateJoints() {} // Override it only if the body part includes joints
}
class Head : public BodyPart
{
// Same as you wrote, plus:
public:
virtual void InitialisePart() {
// Code to initialise a Head
}
// Since a Head has no joints, we don't override the CalibrateJoints() method
}
class Hand : public BodyPart
{
// Same as you wrote, plus:
public:
virtual void InitialisePart() {
// Code to initialise a Hand
}
virtual void CalibrateJoints() {
// Code to calibrate the knuckles in the hand
}
}
And then you no longer need any casts. For instance:
for (BodyPart::BodyPartPtr part : cBodyParts) {
part->InitialisePart();
part->CalibrateJoints(); // This will do nothing for Heads
}
As you can see, no casts at all and everything will work fine. This scheme is extensible; if you later decide that you need additional classes inheriting from BodyPart, just write them and your old code will work correctly:
class Torso : public BodyPart
{
public:
virtual void InitialisePart() {
// Code to initialise a Torso
}
// The Torso has no joints, so no override here for CalibrateJoints()
// Add everything else the class needs
}
class Leg : public BodyPart
{
public:
virtual void InitialisePart() {
// Code to initialise a Leg
}
virtual void CalibrateJoints() {
// Code to calibrate the knee
}
// Add everything else the class needs
}
Now you don't need to change the code you wrote previously: the for loop above will work correctly with and Torso or Leg it finds with no need for an update.
The hip bone's connected to the thigh bone...
I take it you have some composite of all the body parts, maybe a Body class.
What do you want the body to do?
Render itself
Serialise
Ouput its volume, or bounding box, or some other metric
Re-orient itself in response to input
Respond to an inverse-kinematic physical model
The list could probably go on. If you know exactly what you want the Body to do you can put that function in the BodyPart base class, and have Body iterate over the composite hierarchical structure of all the connected body parts, calling render, for example.
An alternative is to use a Visitor, which is effectively a way of dynamically adding methods to a static inheritance hierarchy.
As Kerrek SB pointed out this is not feasible at all, but for the sake of answering the actual question, dynamic_cast is what you are looking for.
Use virtual functions, they will simplify a lot your problem.
Else, you can add some methods to distinguish between different types. However, do it only if you cannot do it another way, ie if you cannot do it via virtual functions.
Example 1:
// in BodyPart; to be reimplemented in derived classes
virtual bool isHand() const { return false; }
virtual bool isHead() const { return false; }
// in Hand (similar to what will be in Head)
bool isHand() const { return true; }
// How to use:
BodyPart::pointer ptr = humanBodyVector[42]; // one item from the array
if(ptr->isHand())
processHand(/*cast to hand*/)
else if(ptr->isHead())
// ...
Example 2: let the derived classes handle the cast
// in BodyPart; to be reimplemented in derived classes
virtual Hand* toHand() const { return 0; }
virtual Head* toHead() const { return 0; }
// in Hand (similar to what will be in Head)
Hand* toHand() const { return this; }
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
C++ How to create subclass in class with array
Hi guys, i still learning C++ and face some issues here.
Basically i got a parent class
lets call this parent class as
Vehicle
It got 2 sub class, lets assume they are
Car and Motorcycle
I will create a vehicle object assume vehicle size is 20
Vehicle veh[20]
I will do the following
string vType;
cout << "Please enter your vehicle Type:";
cin >> vType;
so i do a comparision if (vType=="Car")
it will return 4 wheels from the sub class, but how do i declare its 4 wheels at Car and 2 wheels at Motorcycle , i know i need create 2 additional cpp file which is
class Car : public Vehicle
{
private:
int noOfWheels;
public:
computePrice();
}
But how do i set noOfWheels specially to Car as 4 and Motorcycle as 2.
The next is the tricky part.. after knowing how many wheel it is
i will need store a array for each wheel
string wheel[4];
since i know there 4 wheel in cars.
How do i prompt 4 type and store it in an array, and all of this in an object call Vehicle.
I can use a for loop and thats not the issue, the part i am stuck on is how do i create a string array and store the 4 prompt and then into this Vehicle[0]
wheel 1:
wheel 2:
wheel 3:
wheel 4:
When user want to print data it will be
Vehicle[0]
Type: Car
Wheel: 4
Wheel[0] = Fine condition
Wheel[1] = Need to check again
Wheel[2] = Fine condition
Wheel[3] = Might need get repair
Thanks for all help.
Firstly the declaration for your array is wrong. Since you are dealing with polymorphic classes you need to use pointers.
Vehicle* veh[20];
Otherwise you will have what is called object slicing. Which means that even if you create a Car or a Motorcycle they will be converted into Vehicles when you assign them to your array.
'how do i set noOfWheels specially to Car as 4 and Motorcycle as 2.'
In the constructor
class Car : public Vehicle
{
public:
Car() : noOfWheels(4) { ... }
private:
int noOfWheels;
...
};
class Motorcycle : public Vehicle
{
public:
Motorcycle() : noOfWheels(2) { ... }
private:
int noOfWheels;
...
};
But personally I don't think you need a noOfWheels data member at all. Since the number of wheels is fixed for each type of Vehicle it's a waste of space, instead you need a virtual function
class Vehicle
{
public:
virtual int noOfWheels() const = 0;
...
};
class Car : public Vehicle
{
public:
virtual int noOfWheels() const { return 4; }
...
};
class Motorcycle : public Vehicle
{
public:
virtual int noOfWheels() const { return 2; }
...
};
'how do i create a string array and store the 4 prompt and then into this Vehicle[0]'
Again I would use the constructor to initialize the car wheel names.
class Car : public Vehicle
{
public:
Car(const std::string* w)
{ wheel[0] = w[0]; wheel[1] = w[1]; wheel[2] = w[2]; wheel[3] = w[3]; }
virtual int noOfWheels() const { return 4; }
private:
std::string wheel[4];
...
};
Use constructors to initialize classes. That's what they are for.
Looks like the answer has been accepted, but I typed it all so I will post it all. It's a run down of OOP I guess.
Lets assume that all vehicles have wheels. All those wheels have a condition. Some vehicle have more or less wheels than others.
You need to separate the common aspects of the classes into higher orders, into base classes.
You also need to organize your classes to compose themselves with other classes to build a whole.
Here we have a wheel class, it has a condition, which is a string. You can query it's condition at any time.
class Wheel
{
public:
const std::string GetCondition() const { return mCondition; }
private:
std::string mCondition;
};
We know that a vehicle is going to have wheels, so we store the wheels container here, to share out among the child classes through inheritance.
class Vehicle
{
public:
Vehicle(unsigned int wheelCount) { mWheels.resize(wheelCount, Wheel()); }
virtual unsigned int GetWheelCount() { return mWheels.size(); }
virtual const std::string GetWheelCondition(int wheelNumber)
{
return mWheels[wheelNumber].GetCondition();
}
protected:
std::vector<Wheel> mWheels; // All vehicles have wheels.
};
A car is a type of Vehicle. Therefore it inherits from Vehicle. It has inherited a member that holds Wheel objects. It has also inherited methods that help to find the wheel count and to get the status of a wheel by index. This is the level that you can specialize you classes. The Car and Motorbike class both have wheels, and they have the same core functionality. We can specialize the class by adding or overloading a method.
class Car : public Vehicle
{
public:
Car() Vehicle(4) {}
Car(unsigned int wheelCount) : Vehicle(wheelCount) {}
}
class Motorbike : public Vehicle
{
public:
MotorBike(unsigned int wheelCount) : Vehicle(wheelCount) {}
void DoWheelie() { throw; }
}
We can use these object like so,
Car car(4); // Car with 4 wheels. specialized constructor.
Car standardCar(); // Car with 4 wheels, as default constructor.
Car uberCar(42); // Car with 42 wheels.
Motorbike bike(2); // Bike with 2 wheels.
Motorbike badBike(); // No default constructor defined! Will not compile!
car.GetWheelCount(); // 4
bike.GetWheelCount(); // 2
bike.DoWheelie(); // All good.
car.DoWheelie(); // NOPE! Method doesn't exist for this.
There is more to say on the benefits of polymorphism and heap allocation, but I think I'll leave it here. Hope it's helpful.