Click here to Skip to main content
Click here to Skip to main content

Factory Pattern in C++

, 15 Sep 2012
Rate this:
Please Sign up or sign in to vote.
Using the Factory pattern in C++ to expose only an object's abstract type--hiding the implementation class detail.

Overview

Up until now, I never really used the Factory pattern that often in C++. Recently, I found a use for it in a project I was working on and since I found it useful for my purposes, I thought I might share a tutorial on how the Factory pattern can be used in C++.

Disclaimer: Now I’m not entirely sure how closely my model fits the typical Factory pattern but as far as I understand the Factory pattern, it is pretty close if not exact.

Definition 

Basically a Factory consists of an interface class which is common to all of the implementation classes that the factory will create. Then you have the factory class which is usually a singleton class that spawns instances of these implementation classes.

Abstract Interface Class

So let us create a quick interface class to start with. In this example, I used IAnimal

class IAnimal
{
public:
    virtual int GetNumberOfLegs() const = 0;
    virtual void Speak() = 0;
    virtual void Free() = 0;
}; 

Now for simplicity’s sake, I used a typedef to define a type for the function that is used by the implementation classes to create instances of IAnimal. This typedef is also used in declaring the map that maps the animal name to the function that creates that particular type of animal. You can use whatever calling convention you like, but for this example, I chose __stdcall.

typedef IAnimal* (__stdcall *CreateAnimalFn)(void); 

Specific Implementation Class(es) 

Now come the implementation classes. These are the classes that implement the IAnimal interface. Here’re a few examples:

// IAnimal implementations
class Cat : public IAnimal
{
public:
    int GetNumberOfLegs() const { return 4; }
    void Speak() { cout << “Meow” << endl; }
    void Free() { delete this; }

    static IAnimal * __stdcall Create() { return new Cat(); }
};

class Dog : public IAnimal
{
public:
    int GetNumberOfLegs() const { return 4; }
    void Speak() { cout << “Woof” << endl; }
    void Free() { delete this; }

    static IAnimal * __stdcall Create() { return new Dog(); }
};

class Spider : public IAnimal // Yeah it isn’t really an animal…
{
public:
    int GetNumberOfLegs() const { return 8; }
    void Speak() { cout << endl; }
    void Free() { delete this; }

    static IAnimal * __stdcall Create() { return new Spider(); }
};

class Horse : public IAnimal
{
public:
    int GetNumberOfLegs() const { return 4; }
    void Speak() { cout << “A horse is a horse, of course, of course.” << endl; }
    void Free() { delete this; }

    static IAnimal * __stdcall Create() { return new Horse(); }
};

Factory Class Declaration 

Now comes the Factory class. This is a singleton pattern implementation--meaning only one instance of the factory can ever be instantiated, no more, no less.

// Factory for creating instances of IAnimal
class AnimalFactory
{
private:
    AnimalFactory();
    AnimalFactory(const AnimalFactory &) { }
    AnimalFactory &operator=(const AnimalFactory &) { return *this; }

    typedef map FactoryMap;
    FactoryMap m_FactoryMap;
public:
    ~AnimalFactory() { m_FactoryMap.clear(); }

    static AnimalFactory *Get()
    {
        static AnimalFactory instance;
        return &instance;
    }

    void Register(const string &animalName, CreateAnimalFn pfnCreate);
    IAnimal *CreateAnimal(const string &animalName);
};

Factory Class Implementation

Now we need to work out a few definitions of the AnimalFactory class. Specifically the constructor, the Register, and the CreateAnimal functions.

Constructor

The constructor is where you might consider registering your Factory functions. Though this doesn’t have to be done here, I’ve done it here for the purposes of this example. You could for instance register your Factory types with the Factory class from somewhere else in the code.

/* Animal factory constructor.
Register the types of animals here.
*/
AnimalFactory::AnimalFactory()
{
    Register(“Horse”, &Horse::Create);
    Register(“Cat”, &Cat::Create);
    Register(“Dog”, &Dog::Create);
    Register(“Spider”, &Spider::Create);
}

Type Registration

Now let us implement the Register function. This function is pretty straightforward since I used a std::map to hold the mapping between my string (the animal type) and the create function.

void AnimalFactory::Register(const string &animalName, CreateAnimalFn pfnCreate)
{
    m_FactoryMap[animalName] = pfnCreate;
}

Type Creation

And last but not least, the CreateAnimal function. This function accepts a string parameter which corresponds to the string registered in the AnimalFactory constructor. When this function receives “Horse” for example, it will return an instance of the Horse class, which implements the IAnimal interface.

IAnimal *AnimalFactory::CreateAnimal(const string &animalName)
{
    FactoryMap::iterator it = m_FactoryMap.find(animalName);
    if( it != m_FactoryMap.end() )
    return it->second();
    return NULL;
}

Example Usage Program

int main( int argc, char **argv )
{
    IAnimal *pAnimal = NULL;
    string animalName;

    while( pAnimal == NULL )
    {
        cout << “Type the name of an animal or ‘q’ to quit: “;
        cin >> animalName;

        if( animalName == “q” )
        break;

        IAnimal *pAnimal = AnimalFactory::Get()->CreateAnimal(animalName);
        if( pAnimal )
        {
            cout << “Your animal has ” << pAnimal->GetNumberOfLegs() << ” legs.” << endl;
            cout << “Your animal says: “;
            pAnimal->Speak();
        }
        else
        {
            cout << “That animal doesn’t exist in the farm! Choose another!” << endl;
        }
        if( pAnimal )
            pAnimal->Free();
        pAnimal = NULL;
        animalName.clear();
    }
    return 0;
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Cale Dunlap
Software Developer
United States United States
I'm an interactive software and web developer by day and a video game developer by night. I hold an Associate's degree in Computer Information Systems, a Bachelor's degree in Game and Simulation Programming, and have been writing various types of software since 1999.
 
The programming languages in which I am experienced include C, C++, C#, PHP, Python, and JavaScript--just to name a few. I have experience in creating mobile, embedded, desktop, command-line/console, web, and video game applications for consumer, business, and government/defense purposes.
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
GeneralMy vote of 4 Pinmemberjessierzlz14-Apr-13 14:57 
GeneralMy vote of 5 PinmemberiRaffnix20-Feb-13 20:29 
GeneralMy vote of 5 Pinmembersourabhmehta3-Feb-13 18:34 
GeneralMy vote of 5 PinmemberAnand Todkar17-Sep-12 3:46 
SuggestionThe kind of your factory pattern Pinmemberpasztorpisti16-Sep-12 7:49 
SuggestionWhy the factory pattern is particularly useful in C++ PinmvpEspen Harlinn16-Sep-12 1:22 
QuestionBad code design. PinmemberShurwint15-Sep-12 4:21 
AnswerRe: Bad code design. PinmemberSteve Giancarlo15-Sep-12 6:50 
AnswerRe: Bad code design. PinmemberCale Dunlap15-Sep-12 7:59 
SuggestionRe: Bad code design. Pinmemberpasztorpisti16-Sep-12 2:33 
GeneralRe: Bad code design. PinmemberCale Dunlap16-Sep-12 5:05 
GeneralRe: Bad code design. Pinmemberpasztorpisti16-Sep-12 6:30 
In tutorials its perfectly valid (and good thing) to dismiss the usage of smart pointers and its friends because they are just noise added to the essence of the tutorial. Its true that CryEngine uses a lot of template (maybe too many templates, much more than needed increasing the compile time of the massive codebase) and its not stlport inside CryEngine what I'm talking about, its _smart_ptr. Unlike you I could argue against the power and efficiency of some design choices and accumulated lava-code-crap in some of them, I don't want to say that everything is good that you found in commercial engines (in fact, there are a lot of design mistakes a crap in most of them) but smart pointers and more generally RAII is an exception. I just wanted to point out that smart pointers is not simply a choice of taste. C++ always allows you to use raw memory management and in general resource acquisition and release but you shouldn't do that 'manually' if you have better tools. For example if you allocate an object with new and put the pointer to a simple raw C++ pointer to a local variable inside your function then you have to delete that manually when you return from the function. The problem with this is that you can return at multiple points so you have to put delete statements to a lot of places. You can solve this automatically with an auto pointer. Not to mentiion that in a big company anyone can issue modifications to your code and noone is perfect, so he might forgot to put the necessary delete statements in when he puts in a new return to your function. Lets say you use a raw pointer as a class member, then you have to zero initialize the pointer in your construct and you have to delete it in your destructor. How much easier is it to use an auto ptr and then you are done with the initialization and the deletion as well. This leaves the least space for errors when it comes to heavy refactorization in a big chunk of codepiece. RAII is not only about pointers, its about resources in general. An autoptr is basically a memory resources. But you can easily write auto-ptr like automatic resource release classes for yourself, for example an auto-handle that automatically closes the file handle when you return from the function. Pretty simple, isnt it? I call this 'self healing' code. Or should I call it code that never gets ill? Smile | :) A refcounting pointer is a bit beyond RAII and autoptr because that also involves the shared ownership of an object that comes handy in a lot of cases.
So summing it up: Don't believe that everything is good that you find in commercial bloat-codebases. In fact, most of them contains a lot of crap because big companies change their people relatively often and one might not be able to finish the half done work of someone who just left - resulting in lava code and lava flow. You should make the concept of RAII your own, as a practice write a "smart-handle" that encapsulates a file handle and closes it when your call its close method or when its destructor is called! Smile | :)
AnswerRe: Bad code design. Pinmemberdagronf17-Sep-12 13:08 
GeneralMy vote of 3 PinmemberShurwint15-Sep-12 4:16 
SuggestionNo need for static Create methods [modified] Pinmemberpasztorpisti16-Aug-12 0:20 
SuggestionRe: No need for static Create methods Pinmemberhotpantsexplosion7-Oct-13 10:45 
GeneralRe: No need for static Create methods Pinmemberpasztorpisti7-Oct-13 22:46 
QuestionConfused PinmemberxComaWhitex3-Aug-12 2:19 
AnswerRe: Confused PinmemberCale Dunlap16-Sep-12 5:20 
GeneralRe: Confused PinmemberJoe Pizzi17-Sep-12 15:03 
GeneralRe: Confused PinmemberBlake Miller19-Feb-13 6:57 
QuestionA small problem Pinmemberbeyonddoor21-May-12 3:47 
AnswerRe: A small problem PinmemberCale Dunlap16-Sep-12 5:14 
GeneralMy vote of 5 PinmemberMihai MOGA12-May-12 18:33 
GeneralMy vote of 5 Pinmemberanimageofmine6-May-12 21:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140718.1 | Last Updated 15 Sep 2012
Article Copyright 2012 by Cale Dunlap
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid