Iterate over different objects - c++

I would like to iterate over different objects that all inhereit from the same superclass. That means I have a superclass like this:
class fruit
{
public:
fruit()
{
}
};
And I have subclasses like this, which define the objects that are used in my code:
class apple: public fruit
{
public:
apple()
{
}
};
class banana: public fruit
{
public:
banana()
{
}
};
Now I want to iterate over all fruits (apples, bananas):
for ( first fuit; last fruit; next fruit )
{
// do something, no matter if apple or banana
}
But how should I do this since apples and bananas are different class types, but they share the same superclass. This is why I think, that there has to be an elegant way to do it.

C++ doesn't have any kind of built-in object registry where you can get access to every existing object of a particular type. However, C++ has multiple container types that can be used to store multiple objects in a variety of different data structures.
Since the objects you are storing are of different types but with a common base type, you need to use pointers or references to achieve polymorphic behavior and avoid object slicing.
For example, you can use a vector of std::unique_ptr objects.
std::vector<std::unique_ptr<fruit>> fruits;
fruits.emplace_back(new apple);
fruits.emplace_back(new banana);
for (auto &fruit : fruits) {
// fruit is a reference to the unique_ptr holding the pointer-to-fruit. Use
// the "indirect access to member" operator -> to access members of the
// pointed-to object:
fruit->some_method();
}
The advantage of using this approach (vector of unique_ptr objects) is that your apple and banana objects are automatically destroyed when the vector is. Otherwise, you have to delete them manually, and that is a very error-prone approach.

Related

polymorphism: calling overrided functions without pointers

I am doing some experimentation with C++.
I've been imporessioned by some behaviours with polymorphism.
In other languages (such as c#), when I assign an object based on a derived class to an object of BaseType: this object starts working with the derived class code. Or If I have a list of BaseType objects and I put derived class based objects in it: every element works according to the specific Type.
In c++ no...
I obtained this behaiviour in C++ just using pointers.
Is there an alternative way? Have i missed something?
Here's my code example:
class GenericCar
{
public:
virtual void PrintModelName()
{
std::cout << "No Model Defined \n";
}
};
class FerrariCar : public GenericCar
{
public:
void virtual PrintModelName() override
{
std::cout<<"Ferrari \n";
}
};
int main()
{
std::cout << "Hello World!\n";
//instance of two Ojects: A generic Car (Base Class) and a Ferrari (inherited class)
GenericCar Car = GenericCar();
FerrariCar Ferrari = FerrariCar();
Car.PrintModelName(); //base method
Ferrari.PrintModelName(); //overrided method
((GenericCar)Ferrari).PrintModelName(); //base method....
//declaring a List of Generic Cars (Base Class)
list<GenericCar> ListOfCars;
ListOfCars.push_back(Car); //adding BaseClass based Object
ListOfCars.push_back(Ferrari); //adding InheritedClass based Object
//for each element i want to print the model name of the Car.
for (GenericCar & CarElement: ListOfCars)
{
//The base method is called for each element. (The second object is Ferrari but the base method is executed)
CarElement.PrintModelName();
}
//Now declaring a List of GenericCar pointers
list<GenericCar*> ListOfCarsPointers;
ListOfCarsPointers.push_back(&Car); //adding BaseClass based object address
ListOfCarsPointers.push_back(&Ferrari);//adding InheritedClass based object address
//for each element i want to print the model name of the Car.
for (GenericCar* & CarElement : ListOfCarsPointers)
{
//The correct method is invoked. For the object "Ferrari" is called the overrided function instead of base class code)
CarElement->PrintModelName();
}
//Now i try to assign Ferrari to Car (inherited to base)
Car = Ferrari;//assignment
Car.PrintModelName();//method invoke. Here, the base method is invoked. Not the overridden code...
char c;
std::cin >> c;
}
In C#, for example, the overridden method is called despite the explicit cast to the base class: (BaseClass)InherithedClassObject.method() invokes the overridden method and not the base one.
In the iteration of the list: the overridden method is ivoked, too (Always C#).
In c++ Have I to use always pointer in order to ensure the possibility of having a polymorphic behavior? As a consequence: Have I to manage always memory allocation destroyng objects explicitally?
When you placed Ferrari in your first list you experienced type erasure - the "GenericCar" structure was copied into the list and anything that could have identified that it was a "FerrariCar" was lost.
You need a pointer or reference to invoke polymorphic functions, have a pointer or reference gives you access to the virtual table for your object.
To have a list that could store store such car objects and be passed around to different functions you will probably want to use smart pointers so that you don't wind up with dangling pointers or memory leaks.
#include <memory>
...
list<shared_ptr<GenericCar>> cars;
cars.push_back(shared_ptr<GenericCar>(new GenericCar()));
cars.push_back(shared_ptr<GenericCar>(new FerrariCar()));
for ( shared_ptr<GenericCar> & car : cars )
car->PrintModelName();

How do you downcast from a base object to a child one

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
}

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.

linked lists with inherited classes in c++?

I'm creating a list of classes for a program. However, the base class has multiple children, and some of the children have children as well. Would I need to alter my list in any way to accommodate the inherited classes? Thanks for any help!
Great, thanks for the help! This is an incredibly basic question, but when creating a grandchild class, would this be proper formatting?
Class C: Public B: Public A {
or just
Class C: Public B { ?
Take the following program:
#include <iostream>
#include <list>
struct A
{
virtual void hello()
{ std::cout << "Hello from A\n"; }
};
struct B : public A
{
virtual void hello()
{ std::cout << "Hello from B\n"; }
};
int main()
{
std::list<A> l1;
std::list<A*> l2;
A a;
B b;
l1.push_back(a);
l1.push_back(b);
l2.push_back(&a);
l2.push_back(&b);
l1.front().hello();
l1.back().hello();
l2.front()->hello();
l2.back()->hello();
}
We declare two lists, one using instances of class A, and one using pointers to A. You can put instances of B in the first list, since B is an A (due to inheritance). However, when you try to access the data and methods from items in the first list, you can not access data from B the items thinks they are of class A even if they are not.
For the second list it works though, because of the use of pointers and virtual overloading of the method.
I hope this helps a little with your question.
You are probably not creating a list of classes, but rather of instances of classes. There is a big difference. While a "class" is just the definition of data members and functions, an instance actually fills this definition with life.
That aside, you cannot put an instance of an inherited class into a list that has the parent class as storage type. This only works if you store pointers or references to the instances in the list and allocate the instances themselves elsewhere.
Problem with STL containers and inheritance is that STL containers store copies of objects, so all extended properties of child classes are lost in progress. Solution is to leave objects alone and do not copy them.
In STL containers you can store [smart] pointers to base class, so only pointer will be copied. Or you can go with intrusive lists like Boost::Intrusive or queue.h
it is only :
class C: public B {
and of course :
class B : public A {
C is a subclass of B which is a subclass of A.
if you want a list of a mix of instances of A, B and C, you have to declare it :
list<A*> myClassList;

Dynamic instantiation in C++

I want my code to be extensible, in a way where at runtime I create the objects.
For example, let's say I have a Grocery class which has an array of fruits and I want to fill this array of fruits with objects which derives from fruits.
class Fruit{
};
class Grocery{
std::vector<Fruit*> m_fruits;
};
class Apple: Fruit{
};
class Pineapple: Fruit{
};
Now at runtime I want my Grocery class vector m_fruits to be filled with class objects of Apple and Pineapple. So is it possible in some way.
if I add another fruit as strawberry in future, its object will be created and added to the vector of Grocery dynamically without changing the implementation of Grocery class?
Code help will be appreciated.
Check your textbook. It probably mentions that you can only treat pointers to types polymorphically. In other words, a vector of pointers to fruit can take pointers to apples or pineapples.
Well, if you want to make it so your Grocery class can generate any type of fruit. Even fruit that has been implemented after the grocery class has been locked away, I suppose you might be after something like the following?
typedef Fruit*(*FruitInstantiatorPtr)();
template<class T>
Fruit* FruitInstantiator()
{
return new T();
}
// Then in Grocery have a function like:
static void AddFruitGenerator(FruitInstantiatorPtr instantiatorFunc, string fruitTypeName);
////
//Then someone somewhere can go:
class MyNewFruit:Fruit{};
MyGrocery.AddFruitGenerator(FruitInstantiator<MyNewFruit>, "myAwesomeNewFruit");
And that way your Grocery class will be able to instantiate any type of fruit added in the future.
Assum that Fruit has pure virtual functions (denoted by virtual func() = 0) you would need to store pointers to Fruit objects inside your vector std::vector<Fruit*>.
Unfortunately standard containers aren't particulary good at handling pointers and you will have to delete all objects inside your vector in the destructor of your Grocery. You might consider shared_ptr from TR1 or the boost library.
A word on naming: Instantiation isn't the proper word in this case.
You cannot store objects of a derived type by value in any container of a base type without object slicing occuring.
You need to do one of the following:
Use a vector of raw pointers to the base type, e.g. std::vector<Fruit*> and manage the lifetime of the individual Fruit instances yourself (this is the least desirable option).
Use a vector of smart pointers to the base type, e.g. std::vector<boost::shared_ptr<Fruit> >, and allow reference counting to manage the individual items' lifetimes.
Use boost::ptr_vector<Fruit> to store the items, and the items' lifetime are bound to that of the containing ptr_vector.
Depending on your need, #2 & #3 are preferable. #1 should be avoided, as it involves manual effort to manage the lifetimes and could easily result in memory leaks if done incorrectly.