C++: Create derived instance by 'extending?' base instance / implement downcast? - c++

I have a C++ class which is essentially a container:
class SimpleContainer {
public:
// Various accessor methods / iterators
private:
// The actual content
}
In addition to the SimpleContainer - I want to create a StrictContainer which extends SimpleContainer semantically by enforcing rules on the content, but using the same content as an existing SimpleContainerinstance.
class StrictContainer : public SimpleContainer {
StrictContainer( const SimpleContainer& simple ) {
// Check content in simple, and raise an exception
// if it is not valid.
}
}
Now - my problem is what kind of relationship there should be between the SimpleContainer and the StrictContainer:
is-a:
seems natural; and that is what I have indicated with the inheritance, but then I will create a StrictContainer instance based on extending SimpleContainer instance post construction - is that possible?
has-a
Alternatively I could implement it as a has-a relationship where the StrictContainer has a SimpleContainer member, but then I would need to implement all the accessors and iterators again in the StrictContainer and forward to the SimpleContainer implementation.
The container is quite large; and I would really not copy the content when creating the StrictContainer. I guess what I would like was a way to implement my own downcast operator:
SimpleContainer simple;
// Fill simpleContainer
{
StrictContainer* strict = downcast<StrictContainer>( simple )
...
}
Where the downcast<StrictContainer> would call a method on the StrictContainer to verify the content of the simple input argument?

is-a would be a disaster. Assume the rule is that SimpleContainer contains integers, and StrictContainer only contains odd integers.
StrictContainer strict;
SimpleContainer simple;
strict.insert(1); // OK value is odd
simple.insert(2); // OK simple doesn't check oddness.
SimpleContainer& sc = strict; // Reference to base.
sc.SimpleContainer::insert(2); // Uh-oh. That will use the simple container version
// of insert (even in the presence of virtual functions)
// and will insert an invalid even number into `simple`.
You need has-a

As a third option, I'd suggest a policy based approach as in the following example:
#include<vector>
#include<cassert>
template<typename T>
struct NoCheck {
static bool isOk(T) {
return true;
}
};
template<typename T>
struct TheAnswer {
static bool isOk(T t) {
return false;
}
};
template<>
struct TheAnswer<int> {
static bool isOk(int t) {
return t == 42;
}
};
template<typename T, template<typename> class C = NoCheck>
struct SimpleContainer {
bool add(T t) {
if(C<T>::isOk(t)) {
vec.push_back(t);
return true;
}
return false;
}
private:
std::vector<T> vec{};
};
int main() {
SimpleContainer<int> c1;
assert(c1.add(42));
assert(c1.add(0));
SimpleContainer<int, TheAnswer> c2;
assert(c2.add(42));
assert(not c2.add(0));
}
If having a common interface is a requirement (it's not clear from the question), you can get it with a factory method and a type-erased internal class still based on a policy.

So, restating your requirements:
The StrictContainer has the same interface as the SimpleContainer,
with additions. (This implies an is-a relationship to the
interface.)
Intstantiating a new StrictContainer should not require
copying the SimpleContainer content. (This implies decomposition using a handle.)
Assuming that the lifetime of the original SimpleContainer spans the StrictContainer, this sounds like the decorator pattern. So, if you're willing to do a bit of decomposition -- how about defining an interface like this?
class MyInterface {
// No contained state needed at all.
public:
virtual ~MyInterface() {}
virtual bool getThing1() const = 0;
virtual int getThing2() const = 0;
// and so on...
};
class MyDecorator : public MyInterface {
MyInterface &m_impl; // Could use a smart pointer, if available.
public:
MyDecorator( MyInterface &impl ): m_impl(impl) {}
bool getThing1() const override { return impl.getThing1(); }
int getThing2() const override { return impl.getThing2(); }
// and so on...
};
Then your concrete implementation:
class SimpleContainer : public MyInterface {
bool m_thing1;
int m_thing2;
... // All the real state goes here.
public:
... // All the interface methods go here.
};
Then, the StrictContainer is a lightweight container that retains a handle to the original SimpleContainer, instead of a full copy.
class StrictContainer : public MyDecorator {
// Additional state, if needed.
public:
StrictContainer( SimpleContainer &base ): MyDecorator(base) {}
// Additional methods (like your additional validation method.
};
There's no need for a special "downcast operator", since you already need to call the constructor for StrictContainer and it already does everything you need.
SimpleContainer simple( ... ); // Construct as normal.
StrictContainer strict = simple; // Assuming no extra arguments needed.
Pretty simple.
And yes, you need to write the delegation operations for each method in the interface once in the decorator class. But you could define multiple variants of the StrictContainer class without having to implement them again (unless you want to override some of them).

I prefer implementing something like this using a combination of Adapter and Strategy (Policy) pattern. You can decouple the StrictContainer (which is the adapter) from the underlying container holding the data entirely. Very similar to how std::queue is implemented as an adapter to another container (like vector). You can then parameterize the StrictContainer-adapter with whatever constraints you want to. Whenever you add an element to your container, it is checked whether the constraint is satisfied. If it is, the element is added to the underlying container, otherwise you can do whatever you prefer to (leave the container unchanged or throw an exception for instance).
template<typename T, typename Container, typename Constraint>
class StrictContainer
{
public:
StrictContainer(const Container& container = {}, Constraint constraint = {})
: container_(container), constraint_(constraint)
{
validateAll();
}
StrictContainer(Container&& container, Constraint constraint = {})
: container_(std::move(container)), constraint_(constraint)
{
validateAll();
}
// container interface ...
void push_back(const T& value)
{
if(!constraint_(value))
throw WhateverException();
container_.push_back(value);
}
private:
void validateAll()
{
for(const auto& value : container_)
{
if(!constraint_(value))
throw WhateverException();
}
}
Container container_;
Constraint constraint_;
};
You can then instantiate the StrictContainer like this:
StrictContainer<int, std::vector<int>, IsEvenConstraint<int>> myContainer;
myContainer.push_back(2);
myContainer.push_back(18);
myContainer.push_back(7); // throws
In this case the StrictContainer uses a std::vector as data store, but you could use whatever container you prefer (like your SimpleContainer). The constraints can then be implemented like this
template<typename T>
struct IsEvenConstraint
{
bool operator()(const T& value)
{
return value % 2 == 0;
}
};
Depending on the classes of containers and constraints you like to support you might have to adjust the interface accordingly. Using variadic templates you can extend the StrictContainer to support multiple constraints. You can use a lambda for the constraint as well.
auto lessThanOne = [](float f) { return f < 1.0f; };
StrictContainer<float, std::vector<float>, decltype(lessThanOne)> myContainer2(std::vector<float>{}, lessThanOne);
myContainer2.push_back(0.1f);
myContainer2.push_back(1.7f); // throws

Related

Best way to store std::vector of derived class in a host parent class

I want to store a std::vector<> containing objects which have a common base class, within a host class. The host class should remain copiable since it is stored inside a std::vector<> of it's owner class.
C++ offers multiple ways of doing that, but I want to know the best practice.
Here is an example using std::shared_ptr<>:
class Base{};
class Derivative1: public Base{};
class Derivative2: public Base{};
class Host{
public: std::vector<std::shared_ptr<Base>> _derivativeList_{};
};
class Owner{
public: std::vector<Host> _hostList_;
};
int main(int argc, char** argv){
Owner o;
o._hostList_.resize(10);
Host& h = o._hostList_[0];
h._derivativeList_.emplace_back(std::make_shared<Derivative1>());
// h._derivativeList_.resize(10, std::make_shared<Derivative1>()); // all elements share the same pointer, but I don't want that.
}
Here the main drawback for me is that in order to claim a lot of elements in _derivativeList_ I need to perform emplace_back() for every single element. This takes a lot more time than a simple resize(N) which I can't use with std::shared_ptr<> since it will create the same pointer instance for every slot.
I thought about using std::unique_ptr<> instead, but this is not viable since it makes the Host class non copiable (a feature requested by std::vector).
Otherwise, I could use std::variant<Derived1, Derived2> which can do what I want. However I would need to declare every possible instance of the derived class...
Any thought/advice about this?
tldr: Use a variant or type erasure, depending on context.
What you are asking for in C++ would be described roughly as a value type or a type with value semantics. You want a type that is copyable, and copying just "does the right thing" (copies do not share ownership). But at the same time you want polymorphism. You want to hold a variety of types that satisfy the same interface. So... a polymorphic value type.
Value types are easier to work with, so they will make a more pleasant interface. But, they may actually perform worse, and they are more complex to implement. Therefore, as with everything, discretion and judgment come into play. But we can still talk about the "best practice" for implementing them.
Let's add an interface method so we can illustrate some of the relative merits below:
struct Base {
virtual ~Base() = default;
virtual auto name() const -> std::string = 0;
};
struct Derivative1: Base {
auto name() const -> std::string override {
return "Derivative1";
}
};
struct Derivative2: Base {
auto name() const -> std::string override {
return "Derivative2";
}
};
There are two common approaches: variants and type erasure. These are the best options we have in C++.
Variants
As you imply, variants are the best option when the set of types is finite and closed. Other developers are not expected to add to the set with their own types.
using BaseLike = std::variant<Derivative1, Derivative2>;
struct Host {
std::vector<BaseLike> derivativeList;
};
There's a downside to using the variant directly: BaseLike doesn't act like a Base. You can copy it, but it doesn't implement the interface. Any use of it requires visitation.
So you would wrap it with a small wrapper:
class BaseLike: public Base {
public:
BaseLike(Derivative1&& d1) : data(std::move(d1)) {}
BaseLike(Derivative2&& d2) : data(std::move(d2)) {}
auto name() const -> std::string override {
return std::visit([](auto&& d) { return d.name(); }, data);
}
private:
std::variant<Derivative1, Derivative2> data;
};
struct Host {
std::vector<BaseLike> derivativeList;
};
Now you have a list in which you can put both Derivative1 and Derivative2 and treat a reference to an element as you would any Base&.
What's interesting now is that Base is not providing much value. By virtue of the abstract method, you know that all derived classes correctly implement it. However, in this scenario, we know all the derived classes, and if they fail to implement the method, the visitation will fail to compile. So, Base is actually not providing any value.
struct Derivative1 {
auto name() const -> std::string {
return "Derivative1";
}
};
struct Derivative2 {
auto name() const -> std::string {
return "Derivative2";
}
};
If we need to talk about the interface we can do so by defining a concept:
template <typename T>
concept base_like = std::copyable<T> && requires(const T& t) {
{ t.name() } -> std::same_as<std::string>;
};
static_assert(base_like<Derivative1>);
static_assert(base_like<Derivative2>);
static_assert(base_like<BaseLike>);
In the end, this option looks like: https://godbolt.org/z/7YW9fPv6Y
Type Erasure
Suppose instead we have an open set of types.
The classical and simplest approach is to traffic in pointers or references to a common base class. If you also want ownership, put it in a unique_ptr. (shared_ptr is not a good fit.) Then, you have to implement copy operations, so put the unique_ptr inside a wrapper type and define copy operations. The classical approach is to define a method as part of the base class interface clone() which every derived class overrides to copy itself. The unique_ptr wrapper can call that method when it needs to copy.
That's a valid approach, although it has some tradeoffs. Requiring a base class is intrusive, and may be painful if you simultaneously want to satisfy multiple interfaces. std::vector<T> and std::set<T> do not share a common base class but both are iterable. Additionally, the clone() method is pure boilerplate.
Type erasure takes this one step more and removes the need for a common base class.
In this approach, you still define a base class, but for you, not your user:
struct Base {
virtual ~Base() = default;
virtual auto clone() const -> std::unique_ptr<Base> = 0;
virtual auto name() const -> std::string = 0;
};
And you define an implementation that acts as a type-specific delegator. Again, this is for you, not your user:
template <typename T>
struct Impl: Base {
T t;
Impl(T &&t) : t(std::move(t)) {}
auto clone() const -> std::unique_ptr<Base> override {
return std::make_unique<Impl>(*this);
}
auto name() const -> std::string override {
return t.name();
}
};
And then you can define the type-erased type that the user interacts with:
class BaseLike
{
public:
template <typename B>
BaseLike(B &&b)
requires((!std::is_same_v<std::decay_t<B>, BaseLike>) &&
base_like<std::decay_t<B>>)
: base(std::make_unique<detail::Impl<std::decay_t<B>>>(std::move(b))) {}
BaseLike(const BaseLike& other) : base(other.base->clone()) {}
BaseLike& operator=(const BaseLike& other) {
if (this != &other) {
base = other.base->clone();
}
return *this;
}
BaseLike(BaseLike&&) = default;
BaseLike& operator=(BaseLike&&) = default;
auto name() const -> std::string {
return base->name();
}
private:
std::unique_ptr<Base> base;
};
In the end, this option looks like: https://godbolt.org/z/P3zT9nb5o

Different classes that might be passed to constructor

The constructor of my class can have two different classes passed to it. But there's no way I can know ahead of time what type it will be so I can declare its type as a data member to initialize it. How can I know which kind of object was passed to my constructor. Preferably I would like this to be done without Boost.
I am passing in an iterator. It can either be a const iterator (v.cbegin()) or non-const (v.begin()):
struct iterator
{
iterator(IteratorType it)
: m_it(it)
{ }
IteratorType m_it;
};
Here's how I'm calling the constructor:
iterator X::begin() { return iterator(x.begin()); }
iterator X::begin() const { return iterator(x.cbegin()); }
You do not actually want to know what argument-types were passed to your ctor, because by then the class is already under construction, its type cast in stone.
What you want is to decide on which class to use based on the arguments, which needs earlier intervention.
Still, the solution is simple:
Use a factory-function and a template-class (There are many examples of this pattern in <iterator> and other parts of the standard library)
template<class It>
struct myiterator
{
myiterator(It it) : m_it(it) { }
private:
typename std::iterator_traits<It>::type m_it;
// The above will choke if It is not an iterator
};
template<class... X> auto make_myiterator(X&&.. x)
-> myiterator<typename std::decay<X>::type>
// Only the first arguments type is passed on.
{
using just_making_sure_it_is_an_iterator =
std::iterator_traits<typename std::decay<X>::type>::type;
return {std::forward<X>(x)...};
}
I solved this by using templates as suggested in the comments:
template<typename It>
struct iterator
{
iterator(It it) : m_it(it) { }
private:
It m_it;
};
If your target is to determine which type you are holding in your class, by just holding a more "general" type, then you could do this:
Implement a common interface class of those two classes and use this type as your constructor argument & property. Inside your interface, set up a method contract, that returns your type (i.e. a string or enum value, etc). Then, implement this method to both classes, in different implementation.
public class Iterateable
{
public:
//Ctors/Dtors etc....
//Pure virtual method.
virtual string getType() = 0;
}
public class IteratorType1 : public Iterateable
{
public:
//Ctors/Dtors etc....
string getType {return "IteratorType1";}
}
public class IteratorType2 : public Iterateable
{
public:
//Ctors/Dtors etc....
string getType {return "IteratorType2";}
}
struct iterator
{
iterator(Iterateable it)
: m_it(it)
{ }
Iterateable m_it;
};
You can then hold objects of any type that implement the Iterateable interface.
Then, by calling getType() via the property you can determine the type, as the method implemented on the mostly derived class of the instance holded on the property will be invoked (this is a language feature called late binding).

Container implementation for complex type

I'm trying to come up with a container wrapper which stores data of the following types: bool, int, double, std::string. In addition I have a complex type which I need to store in the container. Let's call it Foo. For the sake of simplicity we'll say that Foo contains a list of ints.
My container class currently wraps an ugly and complex container type which I get from a c api. When I'm finish manipulating the data in the container, I need to copy it back to the api. It uses unions and linked lists. It is possible that I can copy this data into, for example, a std::list, but this might cause performance issues which present themselves at a later date. Therefore, my container class is not dependant on how data is actually stored in memory.
Here's a quick idea of how my container looks:
template <class T>
class Cont
{
public:
Cont(ISetter<T>* setter)
: _setter(setter)
{
}
void sillyFunction(T t)
{
(*_setter)(t,0);
}
private:
...
ISetter<T>* _setter;
};
So I use a helper setter class which handles the nitty gritty of the memory. I have a number of these class but the ISetter will give you an idea of what I'm doing.
In order to deal with the Foo type, which is also stored by the c api in a rather bizarre way, I have arrived at the following setter. Again, this is just a rough example.
class IFoo
{
public:
virtual int getMember() = 0;
};
class Foo2: public IFoo
{
public:
virtual int getMember(){ return 1;} // dummy
};
template<typename T> class ISetter{};
template<> class ISetter<IFoo*>
{
public:
virtual void operator()(IFoo* value, int index) = 0;
};
template<typename T> class Setter{};
template<> class Setter2<Foo2*>: public ISetter<IFoo*>
{
public:
virtual void operator()(IFoo* value, int index)
{
_list[index] = dynamic_cast<Foo2*>(value);
}
private:
std::vector<Foo2*> _list;
};
So I handle my Foo as an interface called IFoo. The Setter2 implementation deals with the setting in memory of my list of Foos. Setter1, missing below, deals with the ugly c api memory.
Here's an idea of these class in practice:
Foo2* f = new Foo2();
ISetter<IFoo*>* setter = new Setter2<Foo2*>();
Cont<IFoo*>* container = new Cont<IFoo*>(setter);
container->sillyFunction(f);
When dealing with ints, for example, I do something like this instead:
int i = 10;
ISetter<int>* setter = new Setter1<int>();
Cont<int>* container = new Cont<int>(setter);
container->sillyFunction(i);
So, my question is if you think this is a good approach and what improvements you might recommend.
I use shared pointers instead of raw pointers.
I would create a single simple Foo wrapper class which can look up members data from the C API, and present it as a coherent class. No need for messing about with interfaces, virtual functions or inheritance for that. Just a single class will do.
So for each "Foo"-entry in the C API, you create a single Foo wrapper.
Then you have simple, well-behaved type representing individual instances of the data stored in your C library.
Now just take that and put it in a std::vector.
struct Foo {
Foo(<handle-or-pointer-to-library-data>);
// member functions for retrieving member data from the C API
};
std::vector<int>
std::vector<bool>
std::vector<std::string>
std::vector<Foo>
As I understand your problem, that would be a simple and efficient solution.
I would change it a little. Consider to remove all this Setter virtual-ism from your code. One of goal to introduce Templates were to have alternative to virtual-ism:
template <class T, class Setter>
class Cont
{
public:
Cont(Setter setter = Setter())
: _setter(setter)
{
}
void sillyFunction(T t)
{
_setter(t,0);
}
private:
...
Setter _setter;
};
And its simple usage:
template <class IType, class Type>
class Setter2_Virtual
{
public:
void operator()(IType* value, int index)
{
_list[index] = dynamic_cast<Type*>(value);
}
private:
std::vector<Type*> _list;
};
Cont<IFoo*, Setter2_Virtual<IFoo, Foo2> > container;
container.sillyFunction(f);
I concentrated on Setters - but maybe you can do the same with IFoo/Foo stuff as well.
Just an idea - you do not obliged to use it after all.

Best way for derived classes to carry different data types in C++

What is the most elegant way to provide an interface in C++ that accepts derived class types that carry with them different data type members that then need to be retrieved later. The example below illustrates this where the Container class provides methods to "post" an Item that will be some kind of derived variant of BaseItem. Later on I want to get the derived Item back and extract its value.
The main thing I want is for the Container interface (post and receive) to stay the same in the future while allowing different "Item" derived types to be defined and "passed" through it. Would template be better for this somehow; I'd rather not use RTTI. Maybe there is some simple, elegant answer to this, but right now I'm struggling to think of it.
class ItemBase {
// common methods
};
class ItemInt : public ItemBase
{
private:
int dat;
public:
int get() { return dat; }
};
class ItemDouble : public ItemBase
{
private:
double dat;
public:
double get() { return dat; }
};
class Container {
public:
void post(int postHandle, ItemBase *e);
ItemBase* receive(int handle); // Returns the associated Item
};
int main()
{
ItemInt *ii = new IntItem(5);
Container c;
c.post(1, ii);
ItemInt *jj = c.receive(1);
int val = jj->get(); // want the value 5 out of the IntItem
}
This is definitely a candidate for generic programming, rather than inheritance. Remember, generics (templates) are ideal when you want identical handling for different data types. Your ItemInt and ItemDouble classes violate OO design principles (the get() method returns different data types depending on what the actual subtype is). Generic programming is built for that. The only other answer would be a tagged data type, and I personally avoid those like the plague.
How about?
template<typename T>
class Item
{
private:
T dat;
public:
T get() { return dat; }
};
class Container {
public:
template<typename T>
void post(int postHandle, Item<T> *e);
template<typename T>
Item<T>* receive(int handle); // Returns the associated Item
};
int main()
{
Item<int> *ii = new Item<int>(5);
Container c;
c.post(1, ii);
Item<int> *jj = c.receive<int>(1);
int val = jj->get(); // want the value 5 out of the IntItem
}
Your Container class looks suspiciously like a std::map. It looks to me like your ItemBase class is just a different name for "Object", the universal base class, which I think is not much different from (or better than) void*. I would avoid trying to contain items of different type in a single container. If your design seems to call for doing so, I'd rethink your design.
A pure template approach doesn't work because you apparently want to have mixed types in your container. You could work with something like Boost's any although I think you need to restore the actual. What I think is called for in this case is a base class exposing the type-independent and virtual methods plus a templatized derived class to hold the actual items:
class Base {
public:
virtual ~Base() {}
virtual void post() = 0;
};
template <typename T>
class Item: public Base {
public:
Item(T const& value): value_(value) {}
void post() { std::cout << "posting " << this->value_ << "\n"; }
private:
T value_;
};
This approach avoids the need to write any derived Item class for another value type. To make creation of these beast easier you probably want to create a suitable creation function as well, e.g.
template <typename T>
std::unique_ptr<Base> make_item(T const& value) {
return std::unique_ptr<Base>(new Item<T>(value));
}
A std::unique_ptr<Base> is returned to make sure that the allocated object is released (if you don't use C++2011 you can used std::auto_ptr<T> instead). This type can easily be converted to other pointer types, e.g. to a std::shared_ptr<Base> which is a better suited to be put into a container.

Instantiating classes by name with factory pattern

Suppose I have a list of classes A, B, C, ... which all inherit from Base.
I get the class name as a string from the user, and I want to instantiate the right class and return a pointer to Base. How would you implement this?
I thought of using a hash-table with the class name as the key, and a function pointer to a function that instantiates the right class and returns a Base *.
However, I think I might be able to use the factory pattern here and make it a lot easier, but I just can't quite remember it well, so I though I'd ask for suggestions.
Here is a generic factory example implementation:
template<class Interface, class KeyT=std::string>
struct Factory {
typedef KeyT Key;
typedef std::auto_ptr<Interface> Type;
typedef Type (*Creator)();
bool define(Key const& key, Creator v) {
// Define key -> v relationship, return whether this is a new key.
return _registry.insert(typename Registry::value_type(key, v)).second;
}
Type create(Key const& key) {
typename Registry::const_iterator i = _registry.find(key);
if (i == _registry.end()) {
throw std::invalid_argument(std::string(__PRETTY_FUNCTION__) +
": key not registered");
}
else return i->second();
}
template<class Base, class Actual>
static
std::auto_ptr<Base> create_func() {
return std::auto_ptr<Base>(new Actual());
}
private:
typedef std::map<Key, Creator> Registry;
Registry _registry;
};
This is not meant to be the best in every circumstance, but it is intended to be a first approximation and a more useful default than manually implementing the type of function stijn mentioned. How each hierarchy should register itself isn't mandated by Factory, but you may like the method gf mentioned (it's simple, clear, and very useful, and yes, this overcomes the inherent problems with macros in this case).
Here's a simple example of the factory:
struct Base {
typedef ::Factory<Base> Factory;
virtual ~Base() {}
virtual int answer() const = 0;
static Factory::Type create(Factory::Key const& name) {
return _factory.create(name);
}
template<class Derived>
static void define(Factory::Key const& name) {
bool new_key = _factory.define(name,
&Factory::template create_func<Base, Derived>);
if (not new_key) {
throw std::logic_error(std::string(__PRETTY_FUNCTION__) +
": name already registered");
}
}
private:
static Factory _factory;
};
Base::Factory Base::_factory;
struct A : Base {
virtual int answer() const { return 42; }
};
int main() {
Base::define<A>("A");
assert(Base::create("A")->answer() == 42);
return 0;
}
the quickest yet very usable way in a lot of areas, would be something like
Base* MyFactoryMethod( const std::string& sClass ) const
{
if( sClass == "A" )
return CreateNewA();
else if( sClass == "B" )
return new CreateClassB();
//....
return 0;
}
A* CreateClassA() const
{
return new A();
}
You could also look into the Boost class factory implementation.
If there's only a few derived classes you can use an "if, else" list.
If you plan to have many derived classes it's better to sort out the class registration process (as Georg mentioned) than to use an "if, else" list.
Here's a simple example using the Boost factory method and class registration:
typedef boost::function<Parent*()> factory;
// ...
std::map<std::string, factory> factories;
// Register derived classes
factories["Child1"] = boost::factory<Child1*>();
factories["Child2"] = boost::factory<Child2*>();
// ...
// Instantiate chosen derived class
auto_ptr<Parent> pChild = auto_ptr<Parent>(factories["Child1"]());
First off, yes, that is just what the factory pattern is for.
(By the way, your other idea is a possible implementation of the factory pattern)
If you intend to do this for a large project (if not, just go with stijns answer), you might want to consider using an associative container somewhere instead of explicit branching and maybe even moving the registration responsibility into the classes to
avoid code changes in one additional place (your factory)
and in turn avoid possibly very long recompilation times (for in-header-implementations) when adding a class
To achieve convenient registration in the classes you could use something like this suggestion and add a function pointer or a functor to the entries that instantiates the derived class and returns a pointer to the base.
If you're not afraid of macros you can then add classes to the factory by just adding one tiny macro to its declaration.