0

On the caller side, I want to pass arbitrary objects of a specific super class via stream operator:

class SubclassA : public Superclass { ... }
class SubclassB : public Superclass { ... } 

...

Container container;
container << SubclassA(param1, param2) << SubclassB(param);

On the callee side, I have to store all passed objects in a vector or list:

std::vector<std::unique_ptr<Superclass>> childs;
Container & operator<<(Superclass const & child) {
  childs.emplace_back(new Superclass(child)); // not possible, since Superclass is abstract 
  return *this;
}

Are there any possibilities to keep the desired behaviour on the callee side, avoiding the need of std::unique_ptr or new keyword?

Edit: Add missing & in stream operator parameter.

Yannic
  • 698
  • 8
  • 22
  • You could always use `std::shared_ptr` and `std::make_shared` or in the case you showed `std::make_unique`, right? Or you want to avoid smart pointer by any chance? – NutCracker Jan 12 '20 at 22:22
  • If possible, I would like to avoid smart pointers completely, but only **on the caller side**. Since this stream function is called very often, it would be much cleaner, if I could pass raw objects as shown in the example. – Yannic Jan 12 '20 at 22:31
  • @NutCracker Using a `shared_ptr` where a `unique_ptr` suffices is always a bad idea. – Acorn Jan 12 '20 at 22:42
  • @JaMiT, although the answer to the referenced question is the same to this answer, the questions are still quite different. IMHO, the two questions are no duplicates. – Yannic Jan 12 '20 at 23:22

1 Answers1

1

You need to add two things to make this work.

First, operator<< needs to take its parameter by reference. Otherwise you have object slicing.

Second, you need to add a virtual clone method to Superclass that is implemented by all the derived classes. This method would make a copy of itself and return the pointer to it.

class Superclass {
public:
    virtual Superclass *clone() const;  // optionally can be abstract
    // ...
};

Container & operator<<(Superclass const &child) {
  childs.emplace_back(child.clone());
  return *this;
}

class SubclassA : public Superclass {
    SubclassA *clone() const override {
        return new SubclassA(*this);
    }
};

This relies on the creation of unique_ptrs from pointers. Since any type of raw pointer is discouraged these days, see this answer for a way to overcome the limitation that smart pointers and covariant return types don't get along and use unique_ptr directly.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56