0

My exact Problem is a bit difficult to explain so heres a simplified Version: I have various Types of Animals (Modules) and a Shelter (ModuleManager). These include Dogs, Cats and Birds. A Owner (Parent) is able to call a function of a shelter which includes a String of the type of Animal he wants to adopt and a List of Generic Items (References) to make the Animals life easier. The List of Items is variable, but must include all and only the required items a spoecific animal needs, which varies from Animal to animal (A dog needs a collar and a leash, A cat needs a cattree and a litterbox a bird needs a cage etc..). This list also includes a reference back to the owner, so the animals knows who it belongs to.

Basicly its should look like this:

Animal * getAnimal(String name, void * Items, int size_items)
//From Customer Class
Parrot * lester=dynamic_cast<Parrot*>(getAnimal("parrot", [this, new Cage()]))

Now what I need is an automated factory pattern which can somehow store Classes in a Key Value array and is able to create instances of them using their constructors which would look like this:

Parrot(void * items)

It should later be possible for a programmer to add new types of Animals to the Shelter during runtime by calling

addAnimal(String Key, Class type)

I hope that explains my problem accurately. Basicly I need a way to create standardized subclasses of a parentclass, where users can add more subclasses without going back to the classic

if x=="Parrot" then return new Parrot(a)
  • Looks like a duplicate of https://stackoverflow.com/questions/9975672/c-automatic-factory-registration-of-derived-types – Parakram Majumdar Jan 02 '18 at 14:09
  • A more detailed explanation without using boost: http://blog.fourthwoods.com/2011/06/04/factory-design-pattern-in-c/ – Parakram Majumdar Jan 02 '18 at 14:10
  • thanks seams usefull – user1510024 Jan 02 '18 at 14:27
  • I undestand you want that user create new animals in run time, for example, dog(), and dog is a new class that inherit from animals but that you no implemented? – Zharios Jan 02 '18 at 14:28
  • I was always puzzled by common OOP example such as animals. Making a parent class animal and child class such as dog or parrot makes very little sense to me. There is not enough commonality between them, and it smells like Java 'Object'. C++ is not this way. – SergeyA Jan 02 '18 at 14:55
  • ->David pretty much. I need a way for a user to inject new Behaviour into my code, and Events are not an elegant way to solve this right now. – user1510024 Jan 02 '18 at 14:59
  • ->Sergey I don't understand your Problem, OOP is just an idea and implemented slightly different in C++ than in Java, but the base Idea is the same. And programming style has nothing to do with the language you are using, people even use OOP in C or Lua. – user1510024 Jan 02 '18 at 15:00
  • -> Parakram Majumdar is there an advantage to using the boost method? Since yours seams a lot more clean – user1510024 Jan 02 '18 at 15:22

2 Answers2

0

If they're all derived from a base class, you can use the factory pattern, e.g., from Modern C++ Design's factory (note, that book is pre-C++11, but this answer updates it for more modern compilers).

The following creates some concrete animals and puts them in a vector and then calls the eat() method on each of them:

#include <memory>
#include <iostream>
#include "factory.h"

struct Animal
{
    virtual ~Animal() = default;
    virtual void eat() = 0;
};

struct Cat : Animal
{
    static constexpr auto ID = 1;
    explicit Cat( const void* ) { }
    void eat() override { std::cout << "Mice\n"; }
};

struct Parrot : Animal
{
    static constexpr auto ID = 2;
    explicit Parrot( const void* ) { }
    void eat() override { std::cout << "Crackers\n"; }

    struct Data
    {
        double age;
        std::string name;
    };
};

// Create the factory object
auto g_factory = MyUtil::Factory<std::unique_ptr<Animal>, int, std::function<std::unique_ptr<Animal>(const void*)>>{};

void RegisterTypesWithFactory()
{
    // Map an ID to a creator function in the factory
    g_factory.Register( Cat::ID,    []( const void* data ) { return std::make_unique<Cat>( data );    } );
    g_factory.Register( Parrot::ID, []( const void* data ) { return std::make_unique<Parrot>( data ); } );
}

int main()
{
    // Configure the factory
    // Note: Registration can be done any time, e.g., later based on input 
    // from a file. I do them all at once here for convenience of illustration.
    RegisterTypesWithFactory();

    // Arbitrary initialization data of differing types 
    // (to be passed as opaque data to ctors with void* or std::any)
    const auto catData  = { 1, 2, 3 };
    const auto birdData = Parrot::Data{ 5.6, "polly" };

    // Create some objects with the factory
    auto       animals  = std::vector<std::unique_ptr<Animal>>{};
    animals.emplace_back( g_factory.Create( Cat::ID,    &catData  ) );
    animals.emplace_back( g_factory.Create( Parrot::ID, &birdData ) );

    // Do something with the objects
    for( const auto& a : animals )
    {
        a->eat();
    }
}

which prints:

Mice
Crackers

See it run live on Wandbox.

BTW, in C++ void* is frowned upon. A suitable replacement may be std::any (or boost::any if you lack C++17).

metal
  • 6,202
  • 1
  • 34
  • 49
  • Seams a bit more caomplicated, but where it says vehicles, shouldn't it say animals? and I don't get what this line of code does: g_factory.Register( Cat::ID, &std::make_unique ); g_factory.Register( Parrot::ID, &std::make_unique ); – user1510024 Jan 02 '18 at 15:21
  • @user1510024 Sorry, I adapted this from a previous answer I wrote. I have updated it now and linked to it running on Wandbox. The calls to `Register()` setup the factory dynamically (i.e., at runtime), which means you could populate the factory only based on what the shelter has available based on user input or a file. – metal Jan 02 '18 at 15:27
  • So you basicly save functions in a key value pair which in turn take the Animalitems and then return the Animal instances? – user1510024 Jan 02 '18 at 15:40
  • @user1510024 Yes. The Wandbox link has source for factory.h, which is updated from Loki's C++03 version. – metal Jan 02 '18 at 15:43
  • @user1510024 You can semi-automate the registration process also. See [this Q&A](https://stackoverflow.com/a/42191109/201787) for more on doing that. I'd do it here, but I see you've already chosen an answer so you've sapped my motivation. ;-) – metal Jan 02 '18 at 15:52
  • Thanks, I'll have a look at it – user1510024 Jan 02 '18 at 15:56
-1

As discussed in the comments, it looks like you are looking for a framework for registering derived types into a factory dispatch. This is actually a very popular pattern, and quite a few similar questions (and answers) exist in stack overflow (eg this one).

A more step-by-step implementation from scratch is explained in this blog, which in turn was inspired by another question on stack overflow.

The advantage of using boost of course, is that a lot of the stuff is already implemented and therefore hidden away from your main code. The disadvantage then is that firstly you need to depend on boost, and secondly, inexperienced programmers might find it obfuscating.