0

I am trying to store objects of inherited types into a std::deque array.

I succeed to store the elements, but when I try to use them, only the parent properties are preserved.

enum Family { parent_, child_};

class Parent {

public:

    double a;

    Family type;

    Parent(double a_, Family type_=Family::parent_) {
        a = a_;
        type = type_;
    }

    void print() {
        std::cout << "I am the parent. a:" << a << std::endl;
    }

};


class Children: public Parent {

public:

    double b;
    double c;

    Children(double a_, double b_, double c_) : Parent(a_, Family::child_) {        
        b = b_;
        c = c_;
    }

    void print() {
        std::cout << "I am the children. a:" << a << ", b:" << b << ", c:" << c << std::endl;
    }
};


void class_inheritance_test() {

    std::deque<Parent> vec;

    vec.push_back(Parent(1.0));
    vec.push_back(Parent(2.0));
    vec.push_back(Children(10.0, 20.0, 30.0));

    for (Parent &e : vec)
        if (e.type == Family::child_){
            Children* ch = static_cast<Children*>(&e);
            ch->print();
        } else {
            e.print();
        }       
}

The output of this piece of code is:

I am the parent. a:1
I am the parent. a:2
I am the children. a:10, b:0, c:-1.30018e-231

Clearly, when I cast back the Children from its storage as a Parent, the properties defined in the Children class are lost.

I see that the problem is either in the way I store the objects or in the way I cast them back to the class they are supposed to be.

I would appreciate some guidance on how to store objects of multiple types in a vector and be able to use them back. The other examples I have seen do not include properties, and for my problem I must have properties.

EDIT ------------------------------

For those in the future, the solution is to use shared_ptr:

void class_inheritance_test() {

    std::deque<std::shared_ptr<Parent>> vec;

    vec.push_back(std::make_shared<Parent>(1.0));
    vec.push_back(std::make_shared<Parent>(2.0));
    vec.push_back(std::make_shared<Children>(10.0, 20.0, 30.0));

    for (std::shared_ptr<Parent> e : vec)
        if (e->type == Family::child_){
            std::shared_ptr<Children> ch = std::static_pointer_cast<Children>(e);
            ch->print();
        } else {
            e->print();
        }       
}

The output is exactly what is expected:

I am the parent. a:1
I am the parent. a:2
I am the children. a:10, b:20, c:30
Santi Peñate-Vera
  • 1,053
  • 4
  • 33
  • 68
  • What you are doing is [object slicing](https://en.wikipedia.org/wiki/Object_slicing), which is probably not what you intended to do? – DarthRubik Jun 30 '18 at 17:41
  • What you probably want to do is either use a `std::variant` or allocate each object somewhere and then instead of a `std::vector` you would have a `std::vector` – DarthRubik Jun 30 '18 at 17:43
  • I need some sort of array to store the objects. In my real-life problem I will have several thousands of objects that compose the different branches of an electrical circuit (i.e. transformers, lines, etc) – Santi Peñate-Vera Jun 30 '18 at 17:49
  • I recommend `std::vector>`. – Eljay Jun 30 '18 at 17:51
  • @Eljay, how will that solve the slicing problem? – Santi Peñate-Vera Jun 30 '18 at 17:53
  • A shared_ptr does not slice. – Eljay Jun 30 '18 at 17:57
  • Very related: https://stackoverflow.com/questions/30019348/storing-two-different-class-objects-in-a-vector And,yes use pointers, better `shared_ptr` instead of objects. – Ripi2 Jun 30 '18 at 18:02

0 Answers0