Question

Is there a way to give an object the possibility to create new objects of it's own type, without specifying this type?

class Foo {
public:
    virtual Foo* new_instance() {
        return new type_of(this); // Some magic here
    }
};

class Bar: public Foo {

};

Foo* a = new Foo();
Foo* b = new Bar();
Foo* c = a->new_instance();
Foo* d = b->new_instance();

I would now like c to be of type Foo, while d should be of type Bar.

Was it helpful?

Solution

Short answer: No, there is no way to make this magic happen.

You could use a macro to make overriding the function in subclasses easier, or create an intermediate class that uses the "curiously recurring template pattern":

template <typename T>
class FooDerived : public Foo
{
public:
    T* new_instance() {
        return new T();
    }
};

class Bar : public FooDerived<Bar>
{
};

Foo* a = new Bar();
Foo* b = a->new_instance(); // b is of type Bar*

But this is most certainly not worth the effort.

OTHER TIPS

Straightforward solution:

class Foo {
public:
    virtual Foo* new_instance() {
        return new Foo();
    }
};

class Bar: public Foo {
public:
    virtual Foo* new_instance() {
        return new Bar();
    }
};

You could use a Mixin to add a factory class. It seems rather complicated for a factory function and is certainly harder to comprehend.

#include <typeinfo>
#include <cassert>
#include <iostream>

template<class T> class WithFactory: public T {
public:
    WithFactory<T>* new_instance() override {
        return new WithFactory<T>( );
    }
};

class FactoryFunction {
    virtual FactoryFunction* new_instance() = 0;
};

class Foo_: public FactoryFunction {
public:
    virtual void f() {
        std::cout << "Foo" << std::endl;
    }
};
typedef WithFactory<Foo_> Foo;

class Bar_: public Foo {
public:
    virtual void f() override {
        std::cout << "Bar" << std::endl;
    }
};
typedef WithFactory<Bar_> Bar;

int main()
{
    Foo* a = new Foo();
    Foo* b = new Bar();
    Foo* c = a->new_instance();
    Foo* d = b->new_instance();

    assert( typeid(a) == typeid(c) );
    assert( typeid(b) == typeid(d) );

    a->f();
    b->f();
    c->f();
    d->f();

    return 0;
}

Output is

Foo
Bar
Foo
Bar

Yes, you just have it do

virtual Foo* new_instance() { return new Foo(); }

And then in each derived class you overload it again to do the same (Although I much prefer the template approach to this sort of thing)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top