2

I am trying to wrap my head around how I would go about implementing the following problem:

I have a parent class called Parent and many different children classes called Child1, Child2, etc. Now what I ultimately want to be able to do is have a std::list or some kind of container to save and access a bunch of different children objects and their derived functions

for example:

Parent.h

class Parent
{
public:
    Parent();

    virtual void logic() = 0;

    //strings and other members of every Child
}

Child1.h

class Child1 : public Gate
{
public:
    Child1 ();
    ~Child1 ();
    void logic();
};

Child1.cpp

void Child1::logic()
{ //Do Stuff }

Now let's say I want to have a std::list or whatever container is best for my Abstract class Parents

main.cpp

std::list <Parent> foo;

how would I go about filling the list up with Children of different types and how would I go about iterating over this list and calling each Child's logic() function?

I read tons of posts about using unique_ptr, using dynamic cast or using a vector instead of a list but at this point, I'm just more confused than I was before.

Student
  • 805
  • 1
  • 8
  • 11

1 Answers1

2

Start off by using std::unique_ptr<Parent> instead of Parent or you'll suffer from object slicing.

Next up, it's just a matter of filling up the container with objects and calling their logic(), for example:

std::vector<std::unique_ptr<Parent>> objects;
objects.push_back(std::make_unique<Child1>());
objects.push_back(std::make_unique<Child2>());
objects.push_back(std::make_unique<Child3>());

for(const auto& child : objects)
  child->logic();

The same can of course be done for a std::list but prefer std::vector here.


#include <iostream>
#include <memory>
#include <vector>
class Parent
{
public:
    Parent() {}

    virtual void logic() = 0;

    //strings and other members of every Child
};

class Child1 : public Parent
{
public:
    void logic() override { std::cout << "Hi from Child1." << std::endl; }
};

class Child2 : public Parent
{
public:
    void logic() override { std::cout << "Hi from Child2." << std::endl; }
};

class Child3 : public Parent
{
public:
    void logic() override { std::cout << "Hi from Child3." << std::endl; }
};

int main() {
    std::vector<std::unique_ptr<Parent>> objects;
    objects.push_back(std::make_unique<Child1>());
    objects.push_back(std::make_unique<Child2>());
    objects.push_back(std::make_unique<Child3>());

    for(const auto& child : objects)
      child->logic();
    return 0;
}

Working example.

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
  • Is there a specific reason why you used std::vector instead of a list? Also would this method work with a QList aswell? I heard QLists dont like Abstract Classes –  Jul 21 '18 at 14:20
  • @Not_very_good Who told you that? AFAIK they work fine. As for std::list vs std::vector read this :https://stackoverflow.com/questions/2209224/vector-vs-list-in-stl , the second answer specifically. – Hatted Rooster Jul 21 '18 at 14:21
  • @Not_very_good The choice of container depends on how you will use the container and the objects in it. – super Jul 21 '18 at 14:22
  • Thanks a ton for the quick answers! –  Jul 21 '18 at 14:23
  • I'm also trying to implement a Map that has the name of the child as the key and points to a specific child in the List from earlier . Would adjusting it to be a Map > be the way to adjust it to your answer? Sorry for the stupid questions, haven't used unique_ptr s much –  Jul 21 '18 at 14:25
  • Actually i think i confused myself with that last comment: if i have a std::vector> and then i'd use a Map > and assign specific Child objects from the Vector to specific keys in the map, wouldn't i have 2 pointers to the same Object? Isn't the point of unique_ptrs that that can't happen? Can i generally only have 1 pointer to any of the Objects in my Vector or can i still have tons of other objects pointing at that specific child in the vector? –  Jul 21 '18 at 15:26
  • So should i use shared_ptr instead if i want both the Vector and the Map to hold pointers to the same specific instances of Child Objects? –  Jul 21 '18 at 15:38
  • I would make destructor of the grand base virtual, in case reference semantics were intended. Pointers - smart or not - may choose to pick pointee's destructor from their static type. Making the base destructor virtual forces late binding of destructor and safegaurds against slicing at destruction. – Red.Wave Jul 21 '18 at 20:03