List for abstact objects - c++

It s my 1st question but it s very improtant for me.
Language: C++, I would like to use
#include <list>
I have the abstract classes:
Organism.
Animal which inherits from Organism.
Plant which inherits from Organism.
Then I have classes like Wolf, Sheep, etc. They all inherit from Animal.
At the end I have classes like Oak, Grass, etc. They all inherit from Plant.
How can I create list having all those elements? list<Organism> my_list;
doesn't work.

In a big shortcut, you have to use polymorphism and your list should contain pointers of base type, which point to concrete objects.
For example:
#include <iostream>
#include <list>
#include <string>
using namespace std;
class Organism
{
public:
virtual string getName() const
{
cout<<"organism"<<endl;
return name;
}
protected:
string name;
};
class Animal : public Organism
{
public:
virtual string getName() const
{
cout<<"animal"<<endl;
return name;
}
};
class Plant : public Organism
{
public:
virtual string getName() const
{
cout<<"plant"<<endl;
return name;
}
};
int main() {
list<Organism*> objects;
Organism *ob1 = new Animal();
Organism *ob2 = new Plant();
objects.push_back(ob1);
objects.push_back(ob2);
for(auto it : objects)
{
it->getName();
}
for(auto it : objects)
{
delete it;
}
return 0;
}

Related

How to get base object's data in a new derived object?

(Beginner in OOP.)
I have a person class which stores the name of the person. In a derived class instance printer, I need that name so that I can do further tasks with it.
#include <iostream>
#include <string>
class Person{
public:
std::string name;
};
class Printer: public Person{
public:
void print(){
printf("%s", this->name.c_str());
}
};
int main() {
Person one;
one.name = "john";
Printer printer;
printer.print();
return 0;
}
What am I not doing to have printer see the data in one ? I'd be having several printer-like objects so storing "john" only once is the goal here.
You have made the member vars public but this is not the right approach for the OOP, the right one is to have them under private access specifier and use setters and getters.
Now to your mistakes:
You use void for main but with c++ you can only use int for it.
You use std::string as an argument for printf but it can't accept it. (I passed the c_string of the std::string to correct that).
You use an object, from the parent class, and give it a name then use another object, from the driven one, to print the name of the first one. (I used only one)
#include <iostream>
#include <string>
class Person{
public:
std::string name;
};
class Printer: public Person{
public:
void print(){
printf("%s",this-> name.c_str());
}
};
int main() {
Printer printer;
printer.name = "name";
printer.print();
}
After your comments, I have updated Printer class to do your inttent
#include <iostream>
#include <string>
class Person{
public:
std::string name;
};
class Printer{
public:
void print(const Person& person ){
printf("%s", person.name.c_str());
}
};
int main() {
Person one;
one.name = "name";
Printer printer;
printer.print(one);
}

C++ program using vector of pointers of inherited classes compile but doesn't run

I have an abstract class called box that only has a string parameter called type and a virtual string that only returns that parameter. This class is the father of another class called Reward that has the constructor that fills the the parameter type and the same function of Box. I'm trying to put them in a class called Board that is basically a vector of the pointers of these classes, I have a constructor that just fills the vector with rewards. The problem comes that I compille it but doesn't run and I cannot find where is the problem. Thanks
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Box{
protected:
string type;
public:
virtual string getType()=0;
};
class Reward : public Box{
public:
string getType(){
return type;
}
Reward(){
type = "Reward";
}
};
class Board{
private:
vector<Box *> Table;
public:
Board(){
for (int i=0;i<=30;i++){
Table[i]=new Reward;
}
}
string getBoxes(int i){
return Table[i]->getType();
}
};
int main(){
Board game;
string toPrint=game.getBoxes(2);
cout<<toPrint;
return 0;
}

Linkedlist contain differnt classes of object in cpp

How we can create a linked list which can contain a different class of object. for example, if a person is base class and it has student and teacher as a derived class so How I can create a linked list which can contain both classes of objects like student also and teacher also.
LinkedList example for understanding my problem:
head->studentobject->teacherobject->studentobject->teacherobject... so on
Try it here. A std::list is a linked list . .
#include <list>
#include <iostream>
#include <memory>
using namespace std;
class Person {
public:
virtual ~Person() = default;
virtual void talk()=0;
};
class Student : public Person {
public:
void talk() {
cout << "Teach me!\n";
}
};
class Teacher : public Person {
public:
void talk() {
cout << "Listen!\n";
}
};
int main() {
list<std::unique_ptr<Person>> people;
people.push_back(unique_ptr<Person>(new Student()));
people.push_back(unique_ptr<Person>(new Teacher()));
for (auto& p : people) {
p->talk();
}
return 0;
}
Usually you would create a base class and derived classes:
#include <iostream>
#include <list>
#include <memory>
class Base {
public:
virtual ~Base() = default;
virtual void printClass() = 0;
};
class Student : public Base {
public:
virtual void printClass() { std::cout << "Student\n"; }
};
class Teacher : public Base {
public:
virtual void printClass() { std::cout << "Teacher\n"; }
};
class Node {
public:
void setTeacher() {
data = std::make_unique<Teacher>();
}
void setStudent() {
data = std::make_unique<Student>();
}
void printClass() { data->printClass(); }
private:
std::unique_ptr<Base> data;
};
int main() {
std::list<Node> l;
l.push_back({});
l.front().setTeacher();
l.front().printClass();
}
Use some kind of pointer to store the references. You can use raw pointers, references, smart pointers, ...
Here you can read when to use virtual destructors

Why does this call to `getNoise` use the base class implementation and not the subclass implementation?

The problem
My understanding was that we could achieve polymorphim by making getNoise virtual in the base, and then overriding it in any subclasses. Then via a vector of pointers, we store the address of the base classes which are used to call methods on such as getNosie below.
Could anybody tell me why my code doesn't do this?
The code
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Animals {
private:
std::string noise = "None";
public:
Animals() = default;
virtual ~Animals() = default;
virtual std::string getNoise() {
return noise;
}
};
class Duck : public Animals {
private:
std::string noise = "Quack!";
public:
using Animals::Animals;
std::string getNoise() override {
return noise;
}
};
class Dog : public Animals {
private:
std::string noise = "Bark!";
public:
using Animals::Animals;
std::string getNoise() override {
return noise;
}
};
class AnimalsContainer {
public:
std::vector<Animals *> animals;
Animals *front;
AnimalsContainer() {
Duck duck;
Dog dog;
animals.push_back(&duck);
animals.push_back(&dog);
front = animals[0];
}
~AnimalsContainer() = default;
};
int main() {
AnimalsContainer animals;
cout << animals.front->getNoise() << endl;
Expected output
I'm expecting
Quack!
But I'm getting
None
"std::string noise" should only be declared in the base class, not in the subclasses. Set the noise value in the constructors of the subclasses instead.
Why dont't you use pointers:
Duck* duck = new Duck();
Dog* dog = new Dog();
animals.push_back(duck);
animals.push_back(dog);
Instead of
Duck duck;
Dog dog;
animals.push_back(&duck);
animals.push_back(&dog);
You can then destroy them on the destructor:
~AnimalsContainer() {
for (Animals* a : animals) {
delete a;
}
}
If you really need noise string "none" in the base class.
Of course the raw pointers are for simplicity, you should maybe use smart pointers.

How to declare a vector list of abstract class in C++? [duplicate]

This question already has answers here:
Why doesn't polymorphism work without pointers/references?
(6 answers)
What does slicing mean in C++?
(4 answers)
How to use polymorphism to access derived class vector member from base class?
(1 answer)
Closed 3 years ago.
I have several classes that inherit from one main class. For the sake of simplicity, I have over-simplified the class definitions to make it short and direct to the point.
animal.h
main class which all other classes inherit from:
class Animal {
protected:
string name;
public:
Animal(string name);
virtual string toString() { return "I am an animal"; }
};
bird.h
class Bird: public Animal {
private:
bool canFly;
public:
Bird(string name, bool canFly = true)
: Animal(name) // call the super class constructor with its parameter
{
this->canFly = canFly;
}
string toString() { return "I am a bird"; }
};
indect.h
class Insect: public Animal {
private:
int numberOfLegs;
public:
Insect(string name, int numberOfLegs) : Animal(name) {
this->numberOfLegs = numberOfLegs;
}
string toString() { return "I am an insect."; }
};
Now, I need to declare a vector<Animal> that will hold several instances of each inherited class.
main.cpp
#include <iostream>
#include "animal.h"
#include "bird.h"
#include "insect.h"
// assume that I handled the issue of preventing including a file more than once
// using #ifndef #define and #endif in each header file.
int main() {
vector<Animal> creatures;
creatures.push_back(Bird("duck", true));
creatures.push_back(Bird("penguin", false));
creatures.push_back(Insect("spider", 8));
creatures.push_back(Insect("centipede",44));
// now iterate through the creatures and call their toString()
for(int i=0; i<creatures.size(); i++) {
cout << creatures[i].toString() << endl;
}
}
I expected the following output:
I am a bird
I am a bird
I am an insect
I am an insect
but I got:
I am an animal
I am an animal
I am an animal
I am an animal
I know this has to do with the line 'vector creatures;. It is calling the constructor for Animal. But my intention is to tell the compiler, that this creaturespoints to an array ofAnimalinherited classes, might beBirdmight beinsect, the point is: they all implement their own unique respective version of toString()`.
What can I do to declare a polymorphic array of objects that are inherited from the same ancestor?
You cannot use a value semantic (read about object slicing). You must use pointers.
Example:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Animal
{
protected:
std::string name;
public:
Animal(std::string name) : name(name)
{
}
virtual std::string toString()
{
return "I am an animal";
}
virtual ~Animal()
{
}
};
class Bird : public Animal
{
private:
bool canFly;
public:
Bird(std::string name, bool canFly = true) : Animal(name) // call the super class constructor with its parameter
{
this->canFly = canFly;
}
std::string toString()
{
return "I am a bird";
}
};
class Insect : public Animal
{
private:
int numberOfLegs;
public:
Insect(std::string name, int numberOfLegs) : Animal(name)
{
this->numberOfLegs = numberOfLegs;
}
std::string toString()
{
return "I am an insect.";
}
};
int main()
{
std::vector<std::unique_ptr<Animal>> creatures;
creatures.emplace_back(new Bird("duck", true));
creatures.emplace_back(new Bird("penguin", false));
creatures.emplace_back(new Insect("spider", 8));
creatures.emplace_back(new Insect("centipede", 44));
// now iterate through the creatures and call their toString()
for (int i = 0; i < creatures.size(); i++)
{
std::cout << creatures[i]->toString() << std::endl;
}
}
prints:
I am a bird
I am a bird
I am an insect.
I am an insect.
I also recommend reading about Sean parent Run Time Polymorphism. The idea is as follows:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Animal
{
public:
struct Interface
{
virtual std::string toString() const = 0;
virtual ~Interface() = default;
};
std::shared_ptr<const Interface> _p;
public:
Animal(Interface* p) : _p(p)
{
}
std::string toString() const
{
return _p->toString();
}
};
class Bird : public Animal::Interface
{
private:
std::string _name;
bool _canFly;
public:
Bird(std::string name, bool canFly = true) : _name(name), _canFly(canFly)
{
}
std::string toString() const override
{
return "I am a bird";
}
};
class Insect : public Animal::Interface
{
private:
std::string _name;
int _numberOfLegs;
public:
Insect(std::string name, int numberOfLegs)
: _name(name), _numberOfLegs(numberOfLegs)
{
}
std::string toString() const override
{
return "I am an insect.";
}
};
int main()
{
std::vector<Animal> creatures;
creatures.emplace_back(new Bird("duck", true));
creatures.emplace_back(new Bird("penguin", false));
creatures.emplace_back(new Insect("spider", 8));
creatures.emplace_back(new Insect("centipede", 44));
// now iterate through the creatures and call their toString()
for (int i = 0; i < creatures.size(); i++)
{
std::cout << creatures[i].toString() << std::endl;
}
}
Problem is with creatures.push_back(Bird("duck", true));
You are creating a Bird object and copying that in the Animal object.
One way is to create objects dynamically so that correct function call can resolve using vtable.
Modify this part of your code and it will work fine.
vector<Animal *> creatures;
creatures.push_back(new Bird("duck", true));
creatures.push_back(new Bird("penguin", false));
creatures.push_back(new Insect("spider", 8));
creatures.push_back(new Insect("centipede",44));
Edit: Make sure to release the memory before creatures goes out of scope.
C++ objects are values with specific types. This differs from many languages where variables always hold references to objects, so they can hold references to derived objects just as easily.
If you copy an instance if a derived class onto an obhect of a base class, you get slicing: only the base class data is copied, and the type of the assignee is still that of the base class.
To achieve polymorphic behaviour in C++ you need to either use std::variant to specify the allowed possibilities, in which case the object will hold one of the options, and will switch type between them when assigned to, or you need to use a pointer to the base class, which can hold a pointer to any derived type, but you must then be wary of memory leaks. You do need to use std::visit or std::get to retrieve the values though.
If you are going to use pointers you should always use std::shared_ptr or std::unique_ptr to manage the objects in order to avoid memory leaks.
Code with variant:
int main() {
vector<std::variant<Bird,Insect>> creatures;
creatures.push_back(Bird("duck", true));
creatures.push_back(Bird("penguin", false));
creatures.push_back(Insect("spider", 8));
creatures.push_back(Insect("centipede",44));
// now iterate through the creatures and call their toString()
for(int i=0; i<creatures.size(); i++) {
cout << std::visit([](auto const& creature){
return creature.toString();
},creatures[i]) << endl;
}
}
Code with pointers:
int main()
{
std::vector<std::unique_ptr<Animal>> creatures;
creatures.emplace_back(std::make_unique<Bird>("duck", true));
creatures.emplace_back(std::make_unique<Bird>("penguin", false));
creatures.emplace_back(std::make_unique<Insect>("spider", 8));
creatures.emplace_back(std::make_unique<Insect>("centipede", 44));
// now iterate through the creatures and call their toString()
for (int i = 0; i < creatures.size(); i++)
{
std::cout << creatures[i]->toString() << std::endl;
}
}
Code with std::shared_ptr is equivalent: just replace unique with shared everywhere.