0

I need to store a bunch of classes in a container element of another class:

#include <list>
#include <cstdlib>
#include <cstdio>

class cont;

class elem {
public:
    virtual void do_something(int *buff) = 0;
};

class myelem1 : public elem {
public:
    virtual void do_something(int *buff) {
        buff[1] = 42;
    }
};

class myelem2 : public elem {
public:
    virtual void do_something(int *buff) {
        buff[2] = 33;
    }
};

class cont {
private:
    int *buff, size;
    std::list<elem> sub;

public:
    cont(int size) : buff((int*)malloc(size*sizeof(int))), size(size) {}
    ~cont() { if (buff) free(buff); }
    void add_worker(const elem &e) {sub.push_back(e);}
    void work() {
        for (elem & e : sub)
            e.do_something(buff);
    }
    void print() {
        for (int i=0; i<size; i++)
            printf("%03d ", buff[i]);
        printf("\n");
    }
};

int main() {
    cont c(10);
    c.add_worker(myelem1());
    c.add_worker(myelem2());
    c.work();
    c.print();
}

The above is a minimal example of what I need to do:

  • I have a class cont with a dataset to be filled.
  • I have a bunch of specific class elem descendants each filling a specific part of dataset.
  • I do not know at compile-time exactly which elements will be filled (main will actually read a config file and instantiate class elem descendants as needed).
  • actual dataset won't be a simple array, of course.
  • compilation of code as above bombs because /usr/include/c++/12/ext/aligned_buffer.h:54:25: error: cannot declare field ‘__gnu_cxx::__aligned_membuf<elem>::_Tp2::_M_t’ to be of abstract type ‘elem’
  • changing line virtual void do_something(int *buff) = 0; to virtual void do_something(int *buff) {}; compiles without errors, but no data in cont::buff is filled.

What am I missing?

ZioByte
  • 2,690
  • 1
  • 32
  • 68
  • You're missing object slicing. This is how objects work in Java and C#, but not in C++. Objects in C++ don't work this way. See the linked question for more information. – Sam Varshavchik Sep 04 '22 at 20:26
  • @SamVarshavchik Actually I understood the problem (essentially assigning a class calls a copy constructor and thus loses actual (sub)class specificity) even before reading answers. Problem is: how do I overcome the problem? What is the right pattern in C++? The only thing I could think is using `unique_ptr`, but that seems over-complex... or is it the right way to go? – ZioByte Sep 04 '22 at 22:58
  • That's certainly the most common solution; depending on the individual circumstances someimes a `std::shared_ptr` is used, instead. This would allow list elements to be pulled out and stashed away somewhere, for further work, without worrying about having the rug pulled out from under you, by deleting them from the list. – Sam Varshavchik Sep 04 '22 at 23:10

0 Answers0