6

I have a class of the following design:

class Meal {
public:
    virtual void cook() = 0; // pure virtual
}

class Omelette : Meal {
public:
    void cook() {/*do something*/}; // non-virtual
}

class Waffle : Meal {
public:
    void cook() {/*do something*/}; // non-virtual
}

std::vector< std::unique_ptr<Meal> > menu;

void addMeal(const Meal& meal) {
    menu.emplace_back(new Meal(meal)); // cannot allocate an object of abstract type
}

I'm unable to find a way of adding a Meal-derived object to the menu since I cannot create an abstract object. Is there a way of performing the above code? I'd prefer that Meal remain abstract. I could pass in a pointer to an existing Meal-derived object, but then my unique_ptr is hardly unique.

nwn
  • 583
  • 7
  • 23
  • 4
    Pass in a `unique_ptr`; `emplace_back` will move it into the vector. This is how you document transfer of ownership. Or, use `shared_ptr` for shared ownership - whichever best suits the rest of your design. – Igor Tandetnik Jan 04 '14 at 19:43
  • 1
    Add a virtual function called `clone` and make each derived class implement that. Use that function in your `addMeal` function. – Vite Falcon Jan 04 '14 at 19:44
  • Delegating non-expiring pointer creation to the code that knows which object they operate with should work, as @IgorTandetnik says – Erbureth Jan 04 '14 at 19:45
  • This is where [factory pattern](http://www.sourcetricks.com/2008/05/c-factory-pattern.html) comes in handy – smac89 Jan 04 '14 at 20:10

2 Answers2

4

The solution to this problem is the virtual copy constructor; which is not allowed in C++ (It is not allowed because constructor is something related to the class itself, it can't be delegated to class's children). That why clone is the best fit for this problem.

Here is a similar answer, with most popular syntax.

So, you code shall be

class Meal {
public:
    virtual void cook() = 0; // pure virtual
    virtual Meal* clone() const = 0; // pure virtual clone.
};

class Omelette : public Meal {
public:
    void cook() {
    /*do something*/ 
    }; // non-virtual
    virtual Omelette* clone() const
    {
        return new Omelette(*this);
    }
};

class Waffle : public Meal {
public:
    void cook() {
        /*do something*/
    }; // non-virtual
    virtual Waffle* clone() const
    {
        return new Waffle(*this);
    }
};

std::vector< std::unique_ptr<Meal> > menu;

void addMeal(const Meal& meal) {
    menu.emplace_back( meal.clone() ); // cannot allocate an object of abstract type
}
Community
  • 1
  • 1
Yousf
  • 3,957
  • 3
  • 27
  • 37
2

You could implement a getNew virtual method which returns a new copy of the (derived) object and use that instead.

user2345215
  • 637
  • 5
  • 9