Nick
Nick

Reputation: 10499

How to design my class?

I have two class that inherit the same abstract base class:

class base
{ virtual void something() = 0; };

class a : public base
{
     void something();
};

class b : public base
{
     void something();

     // This is what I want: a list where I can store values of type a
     // and of type b
     // std::list<a & b> objs;
};

I could use a list of raw/smart pointers (list<base*> obj_ptrs), but how to use this list?

b b_obj;
b_obj.obj_ptrs.push_back(new a());

// Who have to delete this pointer? Who use the class or who design
// the class in the object destructor?

// The following is valid for c++11
auto p = b_obj.obj_ptrs.back();
// But if i'm using c++03?

I want that who use the class have the possibility to do this:

a a_obj;
b b_obj;

b_obj.obj_ptrs.push_back(a);
b_obj.obj_ptrs.push_back(b);

How have I to design my classes to do this work?

Upvotes: 2

Views: 219

Answers (4)

Mike Seymour
Mike Seymour

Reputation: 254431

I could use a list of raw/smart pointers (list<base*> obj_ptrs), but how to use this list?

You would interact with them polymorphically by calling virtual functions or, in exceptional circumstances, using dynamic_cast to convert the pointer type to a* or b*.

Who have to delete this pointer?

You will have to decide on the ownership scheme. One approach is to store smart pointers (usually unique_ptr, or perhaps shared_ptr in special circumstances) in the list, and then they'll be automatically deleted on removal from the list. Another approach is to manage the objects separately from the list, and just put raw pointers in the list.

// The following is valid for c++11
auto p = b_obj.obj_ptrs.back();
// But if i'm using c++03?

That's equivalent to base * p = b_obj.obj_ptrs.back();. auto will not magically give the dynamic pointer type, it's just a shortcut for the static pointer type.

How have I to design my classes to do this work? (storing objects of different types)

Storing objects of different types can be done using a discriminated union - basically, a union with some extra metadata to keep track of which union member is active. These are quite tricky to implement in C++, but you could use Boost.Variant or Boost.Any. This has the advantage that you don't need a common base class, or any other support from the types being stored; any set of (non-abstract) types can be used.

Upvotes: 4

Luc Danton
Luc Danton

Reputation: 35449

If you really, really only care to store values of types a or b and those types only then consider having one std::list<a> and one std::list<b> internally and overloading an appropriate public member on both a and b that forward to the appropriate list (e.g. such that b obj; obj.push_back(value); would be the preferred usage).

This work as long as you don't care about the relative order of insertions between a and b objects, doesn't require you to worry about ownership, doesn't pay the cost of dynamic allocations compared to using e.g. std::unique_ptr<base> and expresses the closest what you want.

Upvotes: 0

Magnus Hoff
Magnus Hoff

Reputation: 22089

Using a list of shared pointers is pretty safe and pretty easy:

std::list<std::shared_ptr<base>> the_list;

If you keep as your rule that any object you add will be allocated with new, shared_ptr will take care of deletion for you when the object is no longer reference counted. (shared_ptr implements reference counting)

std::shared_ptr<a> my_a(new a);
std::shared_ptr<b> my_b(new b);

the_list.push_back(my_a);
the_list.push_back(my_b);

std::shared_ptr<base> my_object = the_list.back();

Upvotes: 2

ForEveR
ForEveR

Reputation: 55887

std::list<a & b> objs; Incorrect. I think you mean std::list<base*> objs or std::list<base&> objs So, for add element do

a a_obj;
b b_obj;
b_obj.objs.push_back(&a_obj);
b_obj.objs.push_back(&b_obj);
base* p = b_obj.objs.back();

or use references instead pointers.

Upvotes: 0

Related Questions