How do you downcast from a base object to a child one - c++

struct BaseObject
{};
struct HardMonster : BaseObject
{
int Berserk(int);
private:
std::list<BaseObject> MonsterList;
};
I have all the monsters defined as a BaseObject, so it's easier to make a list of them. But when I need to convert the BaseObject into a HardMonster so I can use to the Berserk function. I know, I could do it the easy and just make a temp Hardmonster to calculate the damage from Berserk. But I want to do it the right way.

If you use:
list<BaseObject> MonsterList; //This is where the Object list is defined.
you will be storing only BaseObjects. If you add any object of derived type to the list, you will lose the derived type part in the stored object.
Further reading: What is object slicing?
What you need to store is pointers, preferably smart pointers, to BaseObjects.
std::list<std::shared_ptr<BaseObject>> MonsterList;
From a std::shared_ptr<BaseObject>, you can get a std::shared_ptr<HardMonster> by using dynamic_pointer_cast.
std::shared_ptr<BaseObject> baseObject;
std::shared_ptr<HardMonster> monster = std::dynamic_pointer_cast<HardMonster>(baseObject);
if ( monster )
{
// The cast is successful...
// Use monster
}

Related

Vector in an abstract class

I believe that the question here is similar however I still need more clarification on it.
Let's say I create a vector inside an abstract class (which stores objects of another class). How would I be able to use .pushback() from another class if I can't initialise an object of an abstract class?
Obviously the easiest solution is to put the vector in another class but I need another way. I've read you can do this by storing pointers to those objects in a vector. But can somebody give me an example please?
The purpose of an abstract class is to provide an interface that is then implemented in concrete derived classes.
If you want to push items onto the vector which is a data member of the abstract class, then create an appropriate derived class and then you can create an instance of that derived class, which will thus contain a vector you can add entries to.
class Base{
public:
virtual void do_stuff()=0; // this is an abstract base class
protected:
std::vector<int> data;
};
class Derived: public Base
{
public:
void do_stuff() {
// concrete implementation
data.push_back(42); // can add values to vector inherited from base class
}
};
int main()
{
Derived d;
d.do_stuff(); // will add entries to d.data
}
However, I wonder if that is really what you are trying to achieve.
I could find some existing SO answers, but they were using C++98 code.
The right way to store a vector of abstract base classes, in that base class , is to have a vector of smart pointers to the abstract base class.
First, add the vector, and a virtual destructor
struct AbstractBase {
virtual ~AbstractBase(); // <-- this makes sure these shenanigans don't cause memory leaks
std::vector<std::unique_ptr<AbstractBase>> children;
};
Then push_back new derived classes:
struct Derived1 : public AbstractBase; // defined elsewhere
/*...*/
base.children.push_back(std::make_unique<Derived1>());
//or
auto child = std::make_unique<Derived1>();
base.children.push_back(std::move(child));
It has to be a vector of pointers allocated on the heap because vector doesn't know from the base class how big the derived classes are to store them directly.
It has to be a vector of smart pointers because when you're using pointers and heap allocation, someone has to be responsible for cleaning them up. Smart pointers do that automatically.
Lastly, that virtual destructor there in the abstract base class makes sure that even when you're using pointers that have been casted down to abstract base classes, it will call the right destructor to clean everything up.

Declare a pointer of type base class, but then instantiate it by pointing to a child class. Is this good programming practice?

I'm trying to figure my head around polymorphism and pointers and am following some wonderful videos explaining it (hyperlink if you really care)
He declares class A and class B which inherits from A.
But to instantiate an object of B he does so like this:
A* b = new B;
and it works fine (and he continues to use that method when creating more complex classes, a vector array of base type Shape that contains child classes Square, Circle etc. i.e.
std::vector<Shape*> shapes;
shapes.push_back(new Circle.........
shapes.push_back(new Rectangle.......
It is possible, but is it totally fine (and even recommended) to declare a pointer to an object of a base class, but then instantiate it by pointing to its child class??
I guess I just answered my own question, that the benefit comes from being able to manage collections of different objects by referring to them by their parent class? Is that correct?
Thank you!
but is it totally fine (and even recommended) to declare a pointer to an object of a base class, but then instantiate it by pointing to its child class?
When you use
A* ptr = new B();
instead of
B* ptr = new B();
you are losing just a small amount of information. You cannot use any member functions that are defined in B but not in A. Please note that it is perfectly fine to use virtual member functions declared in A but implemented in B.
If that small amount of loss is OK in your use case, then there is no harm in using A* ptr =. If you would like to be able to preserve the B-ness of the pointer so you can use it to access members that are specific to B, it will be necessary to use B* ptr =.
There is a guiding principles about using pointer/reference types:
When defining a function interface, use a pointer/referene type that is as higher up in the class hierarchy as you can get away with to implement the function.
Given
struct Shape { ... };
struct Circle : Shape { ... };
don't use Circle in the interface of a function if everything you need in the function can be obtained from a Shape.
When you add the next sub-class of Shape,
struct Rectangle : Shape { ... };
that function can be used with a Rectangle too without any change.
When defining a pointer/reference, use a type that preserves as much information as possible.
If there is a function
Circle* someFunction();
then, use
Circle* circlePtr = someFunction();
instead of
Shape* shapePtr = someFunction();
You can use circlePtr for wherever you need a Shape* but you won't be able to use shapePtr wherever you need a Circle*.
You partly answered your question, but there can also be other reasons.
Polymorphism is so you can keep some things abstract. Imagine, for instance, code like this:
Person *actor;
if (occupation == 'nerd') {
actor = new NerdPerson();
}
else if (occupation == 'mortician') {
actor = new MorticianPerson();
}
...
actor->printOccupation();
Clearly that's a made up reason. So it MIGHT be about collections of something, but that's only one reason.

Passing inherited class type as argument

I have got problem with passing inherited class type as argument to method that takes its base class type.
class Base {...}
class Derived : public Base {...}
class Container {
vector<Base*> cont; //1
public:
void addToCont(Base x) { //2
cont.push_back(&x);
}
}
int main() {
Container c;
c.addToCont(Derived(p1,p2)); //3
}
1) I suppose I need to have container of pointers to objects to keep it working
2) Here is error in conversion from Derived to Base
3) I am not supposed to change this call. I tried
Derived d(p1,p2);
c.addToCont(d);
with
addToCont(Base& x)
and it worked for me.
My problem is that I've got 3 derived classes and I don't want to overload the add method 3 times. I guess I will have to add some virtual method or some type-casting to those classes, but I couldn't find anything about that. I am novice in inheritance and quite confused of this. Thanks for all your help.
Some notes:
Must use a vector of pointers to the Base, so that you can handle objects from the hierarchy. Goes without saying that you're probably better off with using some kind of smart pointer instead of raw pointers, but that goes in preferences and how much you love risk.
Using void addToCont(Base x) is wrong because even if you were only adding a Base object, you will be adding a pointer to a local variable (the pass-by-value parameter)
Using void addToCont(Base &x) the way you do it with a local Derived d is wrong too, for the same reasons as before, as soon as d goes out of scope, you're left with a dangling pointer stored in the pointer
Calling addToCont(Derived(...)) passes a temporary object. That must be taken into account when you think about your memory management.
Not sure why you see a need for overloading addToCont for all Derived classes, that's not what you did on void addToCont(Base &x)
The solution (if you keep to the raw pointers) is to do void addToCont(Base *x) there you can pass a pointer to Base or to any Derived. Again, you must be mindful about the memory management. You're Derived object probably needs to be allocated with a new Derived(...) and you must watch about who owns it, and who has responsibility for deleting it (for example, when the Container object is destroyed).
You probably should remember to make virtual the destructor of Base, because you will be destroying Derived objects from Base pointers, and if the destructor is not virtual, the object will only be partially destroyed.
If addToCont(Derived(...)) call is absolutely required, then you might want to consider to use the void addToCont(Base &x) defininition.... but them, you must clone the object before inserting it into the vector:
void addToCont(const Base &x) { //2
cont.push_back(x.clone());
}
But then.. you need a virtual Base *clone() const method to be implemented (at least) in the Derived classes, that will produce a Base pointer with an exact copy of the Derived object, involving extra copies of the objects and extra cloning...
Derived classes are only "possible to use" when they are either references or pointers. If you convert a class to a base-class without a reference or pointer, you won't be able to use it as a derived class later.
If you are actually storing pointers in your container, then I would make it explicit, so:
class Container {
vector<Base*> cont;
public:
void addToCont(Base* x) {
cont.push_back(x);
}
~Container()
{
for(auto a : cont)
{
delete a;
}
}
}
And in main:
Container c;
c.addToCont(new Derived(p1,p2));
Note that in your original code, the Derived(p1, p2) will get destroyed again just after call to addToCont(...), so your array would be pointing to a "dead" element of the Derived class. Which was probably not what you actually wanted (since it's undefined behaviour to ever use that element, and building up a container full of useless elements is pretty pointless)

If I have a collection of superclass type, how do I get all the items of a specific subclass type?

I want to create a collection in C++ of type Parent, where I add different subclasses like Child and Child2, and then get all the elements of X subclass. I tried with a vector, but it happens to destroy polymorphism according to this answer. If I use a collection of pointers, I would have to iterate over it sequentially checking the class of every element, is there a better / more efficient solution?
Here's an example code:
class Parent
{
public:
int id;
Parent(){ id = 8; }
};
class Child: public Parent
{
int foo;
public:
Child(int n){ foo= n; }
};
class Child2: public Parent
{
int bar;
public:
Child2(int n){ bar= n; }
};
Pseudocode:
GenericCollection<Parent> collection; //Full of elements Child and Child2.
This is the method I want to implement:
collection.getElements<Child2>();
Thanks for everything.
You cannot do this with objects because of the object slicing problem. You need to use pointers instead - preferably, smart pointers, such as unique_ptr<Parent>:
GenericCollection<unique_ptr<Parent>> collection;
Now you can implement your getElements method that uses Run-Time Type Information (RTTI) to detect the type of the object pointed to by the smart pointer, and keep only the ones pointing to Child2.
Note that in order to use RTTI your base class Parent needs to have at least one virtual member function. This shouldn't be an issue in your case, because you expect polymorphic behavior.
In C++ you can't directly do what you're asking, because items are stored "by value" in the vector, so you'll only end up with the parent portion of each object while the child-specific parts will be sliced away.
However we may be able to solve your real problem.
If you really need to be able to generate separate lists of child1 and child2 objects, the C++ idiom would be separate vectors to contain each different type.
If however all you need is polymorphism, then you could have a vector of (smart) pointers to the base class, and operate on those polymorphically. If you take this approach don't try to get a list of a specific child's objects but instead utilize an appropriate abstract interface to perform your logic.
In this case you can't. Read about object slicing for more information.
It will only work if you have a collection of pointers. For this I recommend you read about std::unique_ptr.

Creating an array of unlike objects

This is a followup to my last question wherein I need an array of objects which are child classes of one base class. I was suggested I try dynamic_cast but speed is very important in this project.
Here is essentially what I am after.
class Object
{
protected:
int id;
};
class Bike: public Object
{
public:
bike();
private:
int bells;
};
class Car: public Object
{
public:
void drive();
private:
int wheels;
};
I need an array of these objects so I decided to use the base class.
// Imagine I have 10 objects and don't know what they will be
Object* objects[10];
// Let's make the first object
objects[0] = new Car;
I was told dynamic casting was a good idea. The problem is that speed is important and I have instances where I will need to do such operations as:
Car 8 references a bike at index value 3.
Is there any other workaround without dynamic_casting?
EDIT: If I populated the array with a bunch of child classes, how could I access the data of a child class at a specific index. In other words, imagine a bike is at index 8. How could I get the int bells from that object with just the array and index.
It depends on what else you're doing, but you could have an array of structures that store an enumeration that specifies what object type it's storing along with an object pointer.
IE:
class CObject;
enum EObjectType
{
OT_Bike,
OT_Car
};
struct SObjectInfo
{
EObjectType Type;
CObject* Object;
};
When iterating through your array, you can check the type of the object, then static cast the object pointer to the appropriate derived type. I use this approach extensively where it can't be avoided and run-time identification of an object type is absolutely necessary within a generic container.
Why do you need to store objects of different classes in the same array, though, without using polymorphism and virtual methods?
First of all if you need it to be very fast do not create it on the heap with operator new. You need to create them locally if possible.
If you are sure that there will be always your objects than you can change casting to static_cast which is a lot of faster solution.
For me the best idea here is to use Interfaces with pure virtual methods. like:
Class Objects //interface
{
public:
virtual void ride() = 0;
}
and then use a interface as a base class. It is very common in the programming.
If the Objects are unlike, why have a base class?
This link might be of help: http://www.codeproject.com/Articles/23304/High-Performance-Heterogeneous-Container
It looks that your problem requires some run-time overhead, no matter how the implementation would look: this is because at some point the program needs to decide what type it actually stores. Note that you have more alternatives to introducing a bit artificial inheritance, provided you can afford using Boost:
Boost.Variant - if you know all the types that you will be storing in advance
Boost.Any - if you do not