The question is about C++. I have 3 classes: the first, named MovieMaker, is abstract, the second, named Actor, is derived from the first one and the third, named 'Director' derives from Actor. I want to create an array that can hold instances of both Actor and Director.
How can I do that?
-
4A director is an actor?Joseph Mansfield– Joseph Mansfield2013-03-13 13:12:26 +00:00Commented Mar 13, 2013 at 13:12
-
3I know every actor wants to direct, I didn't know it went the other way, too.Barmar– Barmar2013-03-13 13:13:11 +00:00Commented Mar 13, 2013 at 13:13
-
1I know it's not your question, but your inheritance hierarchy sounds a bit suspect. It may be worth considering a different structure. For example, you could try: MovieMaker is a concrete class; Role is abstract; Director and Actor inherit from Role and each MovieMaker has a number of Roles. This is slightly more complex, but would be more flexible and avoid weirdness for directors who don't act.Weeble– Weeble2013-03-13 13:20:47 +00:00Commented Mar 13, 2013 at 13:20
-
Inheritance is not the only tool available. Consider if that's what you really want.andre– andre2013-03-13 13:31:37 +00:00Commented Mar 13, 2013 at 13:31
2 Answers
create an array of MovieMaker pointers. it can hold pointers to derived classes. This technique is called polymorphism - here is a nice tutorial:
3 Comments
Create an array of std::shared_ptr<MovieMaker>, or unique_ptr. In C++, it is usually a good idea to create a std::vector instead of a raw array: so std::vector<std::shared_ptr<MovieMaker>> vec, which you populate like this:
#include <vector>
#include <memory>
// later:
std::vector<std::shared_ptr<MovieMaker>> vec;
vec.push_back( std::make_shared<Actor>() );
vec.push_back( std::make_shared<Director>() );
vec.push_back( std::make_shared<Actor>() );
or, in C++11:
#include <vector>
#include <memory>
// later:
std::vector<std::shared_ptr<MovieMaker>> vec = {
std::make_shared<Actor>(),
std::make_shared<Director>(),
std::make_shared<Actor>(),
};
If you are willing to use boost, a 3rd party library, there are a few other options.
Alternatively, create an array of boost::variant<Actor,Director>, which ignores the class hierarchy and simply stores a type-safe union like construct. boost::variant is a bit trick to use.
As another alternative, boost::any can store anything, and you can query it if what it has is what you want.
8 Comments
std::vector already, which means they are on the free store regardless. I added a level of indirection, which (unless you a trick like boost::variant or boost::any) is required for polymorphic storage in std::vector. I chose shared_ptr rather than raw pointers, because raw pointers are more complex. unique_ptr is another alternative. I stored it in a vector, because vector is a good default container to use -- there are good reasons to use raw arrays, but they are corner cases.std::vector. But if they are, the vector manages their storage, and creating smart pointers (shared_ptr, unique_ptr, or anything else that manages storage) that point to them would create a disaster.vector after shared_ptr -- my bad). Regardless, barring union-type tricks, the only way to store polymorphic instances in C++ is in the free store. I covered a few union-type tricks that lets you store polymorophic instances in automatic storage, but they are trickier than using the free store. What, exactly, do you find missing from my explanation?Derived d; Base &b = d; No free store here, but b acts polymorphically. More generally, if you have a container that holds pointers to a base type, it doesn't matter whether the pointed-to objects are on the free store or not; the pointers act polymorphically. But my objection is exactly what I said in my first comment: the proposed solution makes assumptions about object lifetime management that are not part of the original question. Smart pointers can be a valid part of a design, but they should not be added as a reflex action.