Base object as argument to function which takes derived object - c++

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")
}

The problem
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.
The solution
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;
}
Online demo
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 ?

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 Items. 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]));
}

Related

C++ pointer vs object

Could you please clear up a question for me regarding pointer vs object in C++. I have the below code that has a class called "person" and a list that allows for 100 objects of that class type.
class person {...}
int main {
person* mylist;
mylist = new person[100];
mylist[0].set_name("John")
// ...
}
In this code I can call a method of the class by mylist[0].set_name() meaning (by my understanding) that mylist[0] is an object (hence the . operator to call a method). The code works fine.
I have another project where the "person" class is used as a base class to derive classes "carpenter" and "welder". The derived classes simply overwrite a virtual function called salary in the base "person" class to allow for a different calculation of salary.
person* mylist[100];
mylist[0] = new carpenter;
mylist[0]->set_name("John");
This code works fine as well. My question is - why in the first code I can call the set_name method using the . (meaning mylist[0] is an object) and in the second code I have to use the -> operator (meaning mylist[0] is a pointer to the object)?
T* represents a pointer type, which represents a variable that contains a "reference" (usually a memory address) to some instance of type T. Using a real world comparison, a T* pointer stands to T like a street address stands to a building.
Pointers allow you to refer to some instance owned by some other variable, and you can use a valid, non null instance of T* to read and write on a T. In this, they are similar to another C++ concept, references (written as T&), which allow you to alias variables, but differ significantly from pointers by not being objects in their own regard.
A pointer is, in fact, an object itself, with each pointer variable having its own unique address and being thus storable and referenceable. For instance, you can have pointers to pointers (T**) and references to pointers (T*&), but not pointers to references - pointers exist, while references may not (they are usually implemented as pointers underneath though).
To reflect the this "indirect" nature of pointers, C and C++ provide you with two different operators which allow you to dereference a pointer (* and ->), and to reference a variable (&).
For instance, you may do the following:
struct A { int x; };
// ...
A a {};
A *aptr { &a }; // `&` takes the address of `a` and stores it into the `aptr` variable of type `A*`
aptr->x = 33; // `->` is equivalent here to `(*aptr).x`, a.x is now 33
A a2 {};
A **aptrptr { &aptr }; // pointer to pointer
*aptrptr = &a2; // `aptr` now points to `a2`
operator-> is basically syntactic sugar that avoids you some cumbersome expressions like (*aptr).x.
References, being basically just aliases to something else, do not need any special syntax at all, and are always converted transparently when neeeded:
int x { 33 };
int &xref { x }; // `xref` refers to `x`
xref = 12; // `x` is now 33
int y = xref; // copies `x` into `y`, no special syntax needed
Pointers are also used in the C language to access arrays, which always decay to a pointer as soon as they are referred to in expressions. This is messy and it's one of the reasons std::vector and std::array should always be used in their place when feasible.
int x[33];
x[3] = 44; // equivalent to `*(&x[0] + 3) = 44`
Finally, the "indirect" nature of pointers and references allow C++ to convert a Derived* to a Base*, given that a derived class contains a full instance of its base (it gets more complicated with multiple inheritance though).
Every class that inherits or contains from another class containing virtual methods will include a hidden pointer to a _Virtual Method Table`, a list of pointers to functions which will be used to dispatch the virtual methods to the correct implementation.
PS: in modern C++, you should rarely need raw pointers. The correct approach is to use containers such as std::vector, std::array and std::string, and special pointer-like wrappers called smart pointers (like std::unique_ptr) every time you need a pointer for some reason. These will handle the lifetime of a pointer for you, avoiding memory leaks and vastly simplifying memory handling. For the same reason, the new operator should be mostly considered as being deprecated and should not be used at all (unless in placement new expressions, are potentially dangerous if used improperly).
basically the first case works like this: you have an array of objects. To access the object fields and methods you use . operator.
In the second case you have an array of pointers to an object. Pointer is just a memory address, that points to an object of some type. In your case, this is an array of pointers to class person. By default, these pointers are invalid; you have to set them to the address of some existing object. new creates an object on the heap, and returns you an address of that object. In order to access the value behind the pointer, you have to de-reference it. The syntax is this:
some_type obj;
some_type* ptr = &obj; // get the address of the object
(*ptr).some_method(); // de-reference the pointer and call it
ptr->some_method(); // same

How do you add abstract base class unique_ptrs to a map?

I'm currently programming a game in C++. This game features a GameManager class. The GameManager class contains a map that holds pointers to game objects. I have defined a GameObject class that is an abstract class acting simply as an interface.
I have defined two classes that derive from the GameObject class: Enemy and Loot.
I want my GameManager class to contain a map of game objects, or rather, pointers to game objects. Because my GameManager owns these objects, I want the map to contain std::unique_ptr's.
However, I'm having a difficult time actually adding derived objects (e.g. Enemy and Loot) to this map.
I want my GameManager to iterate over the game objects and call the abstract methods. Essentially, my GameManager does not care whether or not something is an enemy, loot, or whatever, it just wants to be able to call the "draw" method as declared in the base class.
How would I go about adding a unique_ptr, that points to a derived class, to a map that contains unique_ptr's to the base class? My attempts so far lead to code I can't compile. I keep getting an error that states I am not allowed to dynamically cast a derived class pointer to a base class pointer.
I feel like this work fine if I was using raw pointers, but I'm intent on using smart pointers.
Code:
#include <memory>
#include <map>
class GameObject
{
public:
virtual void draw() = 0;
};
class Enemy : GameObject
{
public:
void draw() {};
};
class Loot : GameObject
{
public:
void draw() {};
};
int main()
{
std::map<int, std::unique_ptr<GameObject>> my_map;
// How do I add an Enemy or Loot object unique_ptr to this map?
my_map[0] = dynamic_cast<GameObject>(std::unique_ptr<Enemy>().get()); // doesn't compile, complains about being unable to cast to abstract class
return 0;
}
The first cause of an error message is that a class type can never be used as the type for a dynamic_cast. The target type of dynamic_cast must always be either a pointer to class type (meaning the result is null if the cast fails) or a reference to class type (meaning to throw an exception if the cast fails).
So improvement #1:
my_map[0] = dynamic_cast<GameObject*>(std::unique_ptr<Enemy>().get());
But this won't work because GameObject is a private base class of Enemy. You probably meant to use public inheritance, but (when using class instead of struct) you must say so:
class Enemy : public GameObject
// ...
Next we'll find that the = within the map statement is invalid. The left side has type std::unique_ptr<GameObject>, which does not have any operator= that can take a GameObject* pointer. But it does have a reset member for setting a raw pointer:
my_map[0].reset(dynamic_cast<GameObject*>(std::unique_ptr<Enemy>().get()));
Now the statement should compile - but it's still wrong.
Before getting to why it's wrong, we can make a simplification. dynamic_cast is needed for getting a pointer to derived class from a pointer to base class, or for many other type changes within a more complicated inheritance tree. But it's not needed at all to get a pointer to base class from a pointer to derived class: this is a valid implicit conversion, since every object with a derived class type must always contain a subobject of the base class type, and there's no "failure" case. So the dynamic_cast here can just be dropped.
my_map[0].reset(std::unique_ptr<Enemy>().get());
The next problem is that std::unique_ptr<Enemy>() creates a null unique_ptr, and no Enemy object is created at all. To create an actual Enemy, we can write instead either std::unique_ptr<Enemy>(new Enemy) or std::make_unique<Enemy>().
my_map[0].reset(std::make_unique<Enemy>().get());
Still wrong, and in a slightly tricky way. Now the problem is that the created Enemy object is owned by the temporary std::unique_ptr<Enemy> object returned by make_unique. The reset tells the std::unique_ptr<GameObject> within the map that it should own a pointer to the same object. But at the end of the statement, the temporary std::unique_ptr<Enemy> gets destroyed, and it destroys the Enemy object. So the map is left with a pointer to a dead object, which is invalid to use - not what you wanted.
But the solution here is that we don't need to mess around with get() and reset() at all. There is an operator= that allows assigning an rvalue std::unique_ptr<Enemy> to a std::unique_ptr<GameObject>, and it does the right thing here. It makes use of the implicit conversion from Enemy* to GameObject*.
my_map[0] = std::make_unique<Enemy>();
(Note if you had a named std::unique_ptr<Enemy>, you would need to std::move it to allow the assignment, as in my_map[0] = std::move(enemy_ptr);. But std::move is not needed above because the result of make_unique is already an rvalue.)
Now this statement is much shorter and more legible, and will actually do what you want.
A comment also suggested the possibility
my_map.emplace(0, std::make_unique<Enemy>());
This is also valid, but there's a possibly important difference: if the map already has an object with key zero, the = version will destroy and replace the old one, but the emplace version will leave the map alone and the just-created Enemy will be destroyed instead.
dynamic_cast can only be used to convert between pointers, and references. GameObject is neither a pointer type, nor a reference type, so you cannot dynamic_cast to it.
You may have intended dynamic_cast<GameObject*> instead. however, you shouldn't dynamic_cast to a (pointer to) a base class. A pointer to derived type is implicitly convertible to the base class pointer. Use static_cast when implicit conversion is not desirable. Furthermore, that conversion is not possible either, since the cast is outside of any member function, and therefore cannot have access to the private base class.
Furthermore, you cannot assign a bare pointer to a unique pointer. To transfer ownership of a bare pointer to a unique pointer, you can use unique_ptr::reset. Howver, you should never store a pointer from unique_ptr::get into another unique pointer. Doing so will result in undefined behaviour when both unique pointers destructors attempt to destroy the same object. Luckily in this case the pointer is value initialized, and therefore null, so the mistake has technically no consequences. But did you use null pointer intentionally? I suspect not.
Inserting a unique pointer to derived object into a map of unique pointers to base is simple. Let ptr be a unique pointer to Enemy:
std::unique_ptr<Enemy> ptr = get_unique_pointer_from_somewhere();
Simply move assign the unique pointer:
my_map[0] = std::move(ptr);
Or, you could use emplace member function of the map.
Finally, destructor unique_ptr<GameObject> will have undefined behaviour if it points to a derived object. To fix, declare the destructor of GameObject virtual.

Call method for objects of derived type

I have some type hierarchy :
class GameObject{...};
class Subject:public GameObject{...};
class Player:public Subject{...};
class Bullet:public Subject{...};
class Enemy:public Subject{...};
In traversing the array of GameObject*, I check the condition and call method foo(*object1, *object2) ( object1 is reference to Bullet, object2 is reference to Player).
std::vector<GameObject*> objects;
// fill array ( pointers to Bullet, Enemy, Player)
foreach(auto obj1 : objects)
{
foreach(auto obj2 : objects)
{
if(obj1.getID() != obj2.getID()
{
foo(*obj1, *obj2);
}
}
}
Also I write some overloaded foo methods :
void foo(GameObject&, GameObject&)
void foo(Bullet&, Player&)
void foo(Bullet&, Enemy&)
But only foo(GameObject&, GameObject&) is called. Why?
These are pointers to GameObject. You dereference them and get objects of type GameObject, and this makes sense. If you dereferenced a pointer to int and got an object of type Apple, that'd be very odd.
GameObject * (a pointer to GameObject) means that there exists some piece of memory that this pointer points to, and this memory should be treated as an object of type GameObject. When you dereference a pointer, you actually get access to that memory, which is obviously treated as GameObject.
foo() overload to be called is chosen during program compilation. And compiler obviously has no idea what are the real types of objects that you pass in your loops so it chooses the only thing it knows for sure.
There are various ways to workaround this problem in general, google "double dispatch" or "visitor pattern".

How do I make a container that holds pointers of any type

This may seem silly, but I'd like to make a container that holds pointers of any type, so that I can store every single pointer in there and then easily delete them later. I tried:
vector<void*> v;
v.push_back(new Dog());
v.push_back(new Cat());
cout << v[0]; // prints mem address
cout << v[1]; // prints another mem address
cout << *v[0]; // compiler yells at me
But apparently you can't dereference void pointers. Is there a way to make a generic container of pointers of any type, without having to make every single class extend a superclass called "Object" or something?
You can implement pointer wrapper a template class which inherits from a common base class and place those to the container instead. Something along the lines:
class pointer_wrapper_base
{
public:
virtual void delete_pointee()=0;
protected:
void *m_ptr;
};
template<class T>
class pointer_wrapper: public pointer_wrapper_base
{
public:
pointer_wrapper(T *ptr_) {m_ptr=ptr_;}
virtual void delete_pointee()
{
delete (T*)m_ptr;
}
};
Once you have this class, you can use poly-variant class for example, which is like variant class, but all the different variations have common base class. I have an implementation here if you want to have a look: http://sourceforge.net/p/spinxengine/code/HEAD/tree/sxp_src/core/utils.h (search for poly_pod_variant):
std::vector<poly_pod_variant<pointer_wrapper_base> > x;
x.push_back(pointer_wrapper<Cat>(new(Cat)));
x[0]->delete_pointee();
Or if you are ok with dynamic allocation for the wrappers, then you can of course just store pointers to pointer_wrap_base to the vector, e.g.
std::vector<std::unique_ptr<pointer_wrapper_base> > x;
x.push_back(std::unique_ptr<pointer_wrapper_base>(new(pointer_wrapper<Cat>)(new Cat)));
x[0]->delete_pointee();
Look into using some of Boost's classes, such as boost::any, http://www.boost.org/doc/libs/1_55_0/doc/html/any.html and their example code, http://www.boost.org/doc/libs/1_55_0/doc/html/any/s02.html
Alternately, look at Boost's variant as well.
In general, learn Boost. It will blow you away and turbo charge your C++ development.
C++ has a static type system. This means that types of all expressions must be known at compile time. The solution to your problem depends on what are you going to do with the objects.
Option 1: Have Cat and Dog derive from a class
This makes sense if all the objects have a common interface, and if you can make them to derive from a class.
std::vector<std::unique_ptr<Animal>> vec; // good practice - automatically manage
// dynamically allocated elements with
// std::unique_ptr
vec.push_back(std::make_unique<Dog>()); // or vec.emplace_back(new Dog());
vec.push_back(std::make_unique<Cat>()); // or vec.emplace_back(new Cat());
std::cout << *v[0];
Option 2: boost::any
This makes sense if the types are unrelated. For example, you storing ints and objects of your class. Obviously you can't make int derived from your class. So you use boost::any to store, and then cast it back to the type of the object. Exception of type boost::bad_any_cast is thrown if you cast to unrelated type.
std::vector<boost::any> vec;
vec.push_back(Dog());
vec.push_back(25);
std::cout << boost::any_cast<int>(vec[1]);
Also, pointers. Solution to "I want manage my memory properly" is "Don't use new and delete" These are the tools to help you doing this, in no particular order:
std::string instead of null-terminated strings
std::vector<T> instead of new T[]
std::unique_ptr<T> instead of raw pointers to polymorphic objects
...or std::shared_ptr<T> if you share them
cout << * ((Dog *)v[0]);
I'm assuming here that your Dog class is stringifiable, otherwise you'll get a different kind of error, but your type conversion problem should be solved by (Dog *) type cast.

How to store different data types in one list? (C++)

I need to store a list of various properties of an object. Property consists of a name and data, which can be of any datatype.
I know I can make a class "Property", and extend it with different PropertySubClasses which only differ with the datatype they are storing, but it does not feel right.
class Property
{
Property(std::string name);
virtual ~Property();
std::string m_name;
};
class PropertyBoolean : Property
{
PropertyBoolean(std::string name, bool data);
bool m_data;
};
class PropertyFloat : Property
{
PropertyFloat(std::string name, float data);
float m_data;
};
class PropertyVector : Property
{
PropertyVector(std::string name, std::vector<float> data);
std::vector<float> m_data;
};
Now I can store all kinds of properties in a
std::vector<Property*>
and to get the data, I can cast the object to the subclass. Or I can make a pure virtual function to do something with the data inside the function without the need of casting.
Anyways, this does not feel right to create these different kind of subclasses which only differ by the data type they are storing. Is there any other convenient way to achieve similar behavior?
I do not have access to Boost.
C++ is a multi-paradigm language. It shines brightest and is most powerful where paradigms are mixed.
class Property
{
public:
Property(const std::string& name) //note: we don't lightly copy strings in C++
: m_name(name) {}
virtual ~Property() {}
private:
std::string m_name;
};
template< typename T >
class TypedProperty : public Property
{
public:
TypedProperty (const std::string& name, const T& data)
: Property(name), m_data(data);
private:
T m_data;
};
typedef std::vector< std::shared_ptr<Property> > property_list_type;
Edit: Why using std::shared_ptr<Property> instead of Property*?
Consider this code:
void f()
{
std::vector<Property*> my_property_list;
for(unsigned int u=0; u<10; ++u)
my_property_list.push_back(new Property(u));
use_property_list(my_property_list);
for(std::vector<Property*>::iterator it=my_property_list.begin();
it!=my_property_list.end(); ++it)
delete *it;
}
That for loop there attempts to cleanup, deleting all the properties in the vector, just before it goes out of scope and takes all the pointers with it.
Now, while this might seem fine for a novice, if you're an only mildly experienced C++ developer, that code should raise alarm bells as soon as you look at it.
The problem is that the call to use_property_list() might throw an exception. If so, the function f() will be left right away. In order to properly cleanup, the destructors for all automatic objects created in f() will be called. That is, my_property_list will be properly destroyed. std::vector's destructor will then nicely cleanup the data it holds. However, it holds pointers, and how should std::vector know whether these pointers are the last ones referencing their objects?
Since it doesn't know, it won't delete the objects, it will only destroy the pointers when it destroys its content, leaving you with objects on the heap that you don't have any pointers to anymore. This is what's called a "leak".
In order to avoid that, you would need to catch all exceptions, clean up the properties, and the rethrow the exception. But then, ten years from now, someone has to add a new feature to the 10MLoC application this has grown to, and, being in a hurry, adds code which leaves that function prematurely when some condition holds. The code is tested and it works and doesn't crash - only the server it's part of now leaks a few bytes an hour, making it crash due to being out of memory about once a week. Finding that makes for many hours of fine debugging.
Bottom line: Never manage resources manually, always wrap them in objects of a class designed to handle exactly one instance of such a resource. For dynamically allocated objects, those handles are called "smart pointer", and the most used one is shared_ptr.
A lower-level way is to use a union
class Property
union {
int int_data;
bool bool_data;
std::cstring* string_data;
};
enum { INT_PROP, BOOL_PROP, STRING_PROP } data_type;
// ... more smarts ...
};
Dunno why your other solution doesn't feel right, so I don't know if this way would feel better to you.
EDIT: Some more code to give an example of usage.
Property car = collection_of_properties.head();
if (car.data_type == Property::INT_PROP) {
printf("The integer property is %d\n", car.int_data);
} // etc.
I'd probably put that sort of logic into a method of the class where possible. You'd also have members such as this constructor to keep the data and type field in sync:
Property::Property(bool value) {
bool_data = value;
data_type = BOOL_PROP;
}
I suggest boost::variant or boost::any. [Related question]
Write a template class Property<T> that derives from Property with a data member of type T
Another possible solution is to write a intermediate class managing the pointers to Property classes:
class Bla {
private:
Property* mp
public:
explicit Bla(Property* p) : mp(p) { }
~Bla() { delete p; }
// The standard copy constructor
// and assignment operator
// aren't sufficient in this case:
// They would only copy the
// pointer mp (shallow copy)
Bla(const Bla* b) : mp(b.mp->clone()) { }
Bla& operator = (Bla b) { // copy'n'swap trick
swap(b);
return *this;
}
void swap(Bla& b) {
using std::swap; // #include <algorithm>
swap(mp, b.mp);
}
Property* operator -> () const {
return mp;
}
Property& operator * () const {
return *mp;
}
};
You have to add a virtual clone method to your classes returning a pointer to a newly created copy of itself:
class StringProperty : public Property {
// ...
public:
// ...
virtual Property* clone() { return new StringProperty(*this); }
// ...
};
Then you'll be able to do this:
std::vector<Bla> v;
v.push_back(Bla(new StringProperty("Name", "Jon Doe")));
// ...
std::vector<Bla>::const_iterator i = v.begin();
(*i)->some_virtual_method();
Leaving the scope of v means that all Blas will be destroyed freeing automatically the pointers they're holding. Due to its overloaded dereferencing and indirection operator the class Bla behaves like an ordinary pointer. In the last line *i returns a reference to a Bla object and using -> means the same as if it was a pointer to a Property object.
A possible drawback of this approach is that you always get a heap operation (a new and a delete) if the intermediate objects must be copied around. This happens for example if you exceed the vector's capacity and all intermediate objects must be copied to a new piece of memory.
In the new standard (i.e. c++0x) you'll be able to use the unique_ptr template: It
can be used inside the standard containers (in contrast to the auto_ptr which must not be used in the standard containers),
offers the usually faster move semantics (it can easily passed around) and
takes care over the held pointers (it frees them automatically).
I see that there are lots of shots at trying to solve your problem by now, but I have a feeling that you're looking in the wrong end - why do you actually want to do this in the first place? Is there some interesting functionality in the base class that you have omitted to specify?
The fact that you'd be forced to switch on a property type id to do what you want with a specific instance is a code smell, especially when the subclasses have absolutely nothing in common via the base class other than a name (which is the type id in this case).
Starting with C++ 17 we have something called as std::variant and std::any.
std::variant
An instance of std::variant at any given time either holds a value of one of its alternative types, or in the case of error - no value.
std::any
The class any describes a type-safe container for single values of any copy constructible type.
An object of class any stores an instance of any type that satisfies the constructor requirements or is empty, and this is referred to as the state of the class any object. The stored instance is called the contained object. Two states are equivalent if they are either both empty or if both are not empty and if the contained objects are equivalent.
The non-member any_cast functions provide type-safe access to the contained object.
You can probably do this with the Boost library, or you could create a class with a type code and a void pointer to the data, but it would mean giving up some of the type safety of C++. In other words, if you have a property "foo", whose value is an integer, and give it a string value instead, the compiler will not find the error for you.
I would recommend revisiting your design, and re-evaluating whether or not you really need so much flexibility. Do you really need to be able to handle properties of any type? If you can narrow it down to just a few types, you may be able to come up with a solution using inheritance or templates, without having to "fight the language".