views:

146

answers:

4

I want my code to be extensible, in a way where at runtime I create the objects.

For example, let's say I have a Grocery class which has an array of fruits and I want to fill this array of fruits with objects which derives from fruits.

class Fruit{

};

class Grocery{

    std::vector<Fruit> m_fruits;
};

class Apple: Fruit{

};

class Pineapple: Fruit{

};

Now at runtime I want my Grocery class vector m_fruits to be filled with class objects of Apple and Pineapple. So is it possible in some way.

The vector may store pointers. The point is not where the objects are stored or created but is it possible that in the future, if I add another fruit as strawberry, its object will be created and added to the vector of Grocery dynamically without changing the implementation of Grocery class?

Code help will be appreciated.

+4  A: 

Check your textbook. It probably mentions that you can only treat pointers to types polymorphically. In other words, a vector of pointers to fruit can take pointers to apples or pineapples.

UM, there's also references (even though they don't apply in this case).
sbi
A: 

Assum that Fruit has pure virtual functions (denoted by virtual func() = 0) you would need to store pointers to Fruit objects inside your vector std::vector<Fruit*>.

Unfortunately standard containers aren't particulary good at handling pointers and you will have to delete all objects inside your vector in the destructor of your Grocery. You might consider shared_ptr from TR1 or the boost library.

A word on naming: Instantiation isn't the proper word in this case.

pmr
A: 

You cannot store objects of a derived type by value in any container of a base type without object slicing occuring.

You need to do one of the following:

  1. Use a vector of raw pointers to the base type, e.g. std::vector<Fruit*> and manage the lifetime of the individual Fruit instances yourself (this is the least desirable option).
  2. Use a vector of smart pointers to the base type, e.g. std::vector<boost::shared_ptr<Fruit> >, and allow reference counting to manage the individual items' lifetimes.
  3. Use boost::ptr_vector<Fruit> to store the items, and the items' lifetime are bound to that of the containing ptr_vector.

Depending on your need, #2 & #3 are preferable. #1 should be avoided, as it involves manual effort to manage the lifetimes and could easily result in memory leaks if done incorrectly.

Nathan Ernst
+1  A: 

Well, if you want to make it so your Grocery class can generate any type of fruit. Even fruit that has been implemented after the grocery class has been locked away, I suppose you might be after something like the following?

typedef Fruit*(*FruitInstantiatorPtr)();

template<class T>
Fruit* FruitInstantiator()
{
   return new T();
}


// Then in Grocery have a function like:

static void AddFruitGenerator(FruitInstantiatorPtr instantiatorFunc, string fruitTypeName);

////
//Then someone somewhere can go:

class MyNewFruit:Fruit{};

MyGrocery.AddFruitGenerator(FruitInstantiator<MyNewFruit>, "myAwesomeNewFruit");

And that way your Grocery class will be able to instantiate any type of fruit added in the future.

matt