Reputation: 183
I want to write a function which takes as an argument an object from the class "Armor", however, when I call the function, I use instead an object from the base class "Item". Of course this object I use, even though may only be considered an "Item", may also be an "Armor". Only when I am sure it is an "Armor", I want to call the function.
In my case, I store items in a vector (these items can be armors). I want to get this item from the vector and call the function with it (equip the item, which I know is an armor).
class Item{
};
class Armor : public Item{
};
void equipArmor(Armor armor){ //Armor class argument
//Equip the armor
}
int main(){
vector<Item> items;
Armor a;
items.push_back(a);
equipArmor(items[0]); //Call function with an "Item" as an argument (even though it is in fact also an "Armor")
}
Upvotes: 0
Views: 51
Reputation: 73376
You have a vector of Item
. When you push_back
an Armor
it will be sliced into an Item
. So in the vector you have no longer an Armor
but just an ordinary Item
.
This is why your code won't work. First you cannot call your equipArmor()
function with an Item
, since it expects an Armor
and downcasting is never implicit. But even if you could, you would always pass an Item
value and never an Armor
value.
To solve your issue, you need to work with pointers (better smart pointers) or references.
The first thing you will need to be able to work with polymorphic types and doing runtime type determination, is to have at least one virtual function in your base class:
class Item{
public:
virtual ~Item() {}
};
Now let's make your vector a vector of shared pointers. The nice thing is that those will ensure that objects will be destroyed when they are no longer used in any shared pointer. So less hassle with memory management, and less hassle with the rule of 3 :
vector<shared_ptr<Item>> items;
shared_ptr<Item> a = make_shared<Armor>();
items.push_back(a);
shared_ptr<Item> i = make_shared<Item>();
items.push_back(i);
equipArmor(items[0]); // lets just try the two possible cases
equipArmor(items[1]);
Finally, in your function, you can then sense for the real type and act accordingly, in a safe manner using dynamic_pointer_cast
:
void equipArmor(shared_ptr<Item> item){ //Armor class argument
shared_ptr<Armor> a = dynamic_pointer_cast<Armor>(item);
if (a) {
cout << "Armor"<<endl;
}
else cout << "Item"<<endl;
}
Remarks
If your type is not polymorphic, you cannot you dynamic_pointer_cast
. You still could cast with a static_pointer_cast
, but this is risky, because it requires you to know for sure that the casted smart pointer has the right type.
If you prefer raw pointers, you the same principles would apply, but yo'ud use dynamic_cast
or static_cast
respectively. But again, static_cast
requires you to be absolutely sure of the type. And how can you be, if you have a vector full of random items ?
Upvotes: 2
Reputation: 1286
You want to cast from the base class (Item
) to the subclass (Armor
). This is impossible.
You could do this if items
would be a vector of pointers to Item
s. You can then cast an Item *
to an Armor *
if you are sure that the underlying object is actually an Armour
.
int main(){
std::vector<Item *> items;
Armor a;
items.push_back(&a);
// This only works if items[0] points to an Armor object
equipArmor(*static_cast<Armor *>(items[0]));
}
Upvotes: 1