Click here to Skip to main content
15,891,033 members
Articles / General Programming

Factory Pattern in C++

Rate me:
Please Sign up or sign in to vote.
4.88/5 (61 votes)
15 Sep 2012CPOL2 min read 346.4K   3.2K   88   65
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

C++
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.

C++
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:

C++
// 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.

C++
// 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.

C++
/* 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.

C++
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.

C++
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

C++
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;
}
This article was originally posted at http://www.caledunlap.com/2010/10/factory-pattern-in-c

License

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


Written By
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, 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.

Comments and Discussions

 
GeneralMy vote of 5 Pin
kanalbrummer12-Aug-21 6:20
kanalbrummer12-Aug-21 6:20 
QuestionThank you! Pin
therealorry7-Jan-21 13:55
therealorry7-Jan-21 13:55 
AnswerClass Factory Using a Template Class and Nonstatic Generator Pin
Dr. Versaeg26-Aug-20 5:52
Dr. Versaeg26-Aug-20 5:52 
QuestionCreateAnimal isn't static Pin
Member 774162320-May-19 3:33
Member 774162320-May-19 3:33 
QuestionReturns only one instance for any animals Pin
jeyasekhar14-Jul-18 6:55
jeyasekhar14-Jul-18 6:55 
AnswerRe: Returns only one instance for any animals Pin
nasev6-Apr-21 12:22
nasev6-Apr-21 12:22 
GeneralMy vote of 3 Pin
Member 131704153-May-17 13:36
Member 131704153-May-17 13:36 
QuestionHow to add common code to specific implementations Pin
Member 85340353-Oct-16 6:32
Member 85340353-Oct-16 6:32 
QuestionI voted 5 Stars! Pin
bholman16-Sep-16 4:16
bholman16-Sep-16 4:16 
Questionnumbered, counted and parametric instances... Pin
LastBlow128-Jul-16 22:05
LastBlow128-Jul-16 22:05 
GeneralMy vote of 5 Pin
Member 43208442-Jan-16 22:56
Member 43208442-Jan-16 22:56 
Questionvery good demo. Pin
haidong83910-Dec-14 10:42
haidong83910-Dec-14 10:42 
QuestionConfiguration File Pin
RBaryolo18-Sep-14 7:48
RBaryolo18-Sep-14 7:48 
GeneralMy vote of 4 Pin
jessierzlz14-Apr-13 14:57
jessierzlz14-Apr-13 14:57 
GeneralMy vote of 5 Pin
iRaffnix20-Feb-13 20:29
iRaffnix20-Feb-13 20:29 
GeneralMy vote of 5 Pin
sourabhmehta3-Feb-13 18:34
sourabhmehta3-Feb-13 18:34 
GeneralMy vote of 5 Pin
Anand Todkar17-Sep-12 3:46
Anand Todkar17-Sep-12 3:46 
SuggestionThe kind of your factory pattern Pin
pasztorpisti16-Sep-12 7:49
pasztorpisti16-Sep-12 7:49 
SuggestionWhy the factory pattern is particularly useful in C++ Pin
Espen Harlinn16-Sep-12 1:22
professionalEspen Harlinn16-Sep-12 1:22 
QuestionBad code design. Pin
Shurwint15-Sep-12 4:21
Shurwint15-Sep-12 4:21 
AnswerRe: Bad code design. Pin
Steve Giancarlo15-Sep-12 6:50
Steve Giancarlo15-Sep-12 6:50 
AnswerRe: Bad code design. Pin
Cale Dunlap15-Sep-12 7:59
Cale Dunlap15-Sep-12 7:59 
Thanks for the feedback, but you have made a critical assumption about how this example factory pattern would be used. First off, I tend to shy away from smart pointers. This is not because I find anything wrong with them necessarily, I've just not dealt with code that utilizes them all that often. Nearly all C and C++ projects on which I've contributed, past and present, leave memory management even at the lowest and most raw level up to the programmer. It is therefore incredibly important that the developer understands the result of certain, critical, calls which deal with object construction and destruction.

The use of smart pointers really comes down to developer preference and/or the intended use of the resulting program or system. While they have their place in some applications, they aren't always a great fit for others (ie: where manual memory management is commonplace. Eg: video game engines, low-level socket communication libraries, and/or other real-time systems).

I opted to avoid smart pointers in this example for a number of reasons. The biggest being that the concept of object lifetime and memory-space ownership is slightly out of scope of the article. It was not my intent to write an article on the importance of memory cleanup and object life-cycle management. I would figure most C/C++ developers would have at least a basic understanding of the topic. There are numerous ways life-cycle management and memory cleanup can be achieved, none of which are exclusive to the the factory design pattern. I simply chose the lowest-level and most primitive form of it. No matter what the strategy may be, the memory is always allocated and freed using either the C functions (malloc, calloc, free, etc.) or by the C++ 'new' and 'delete' keywords. Everything else is just convenience mechanisms that make the job a bit easier by removing that responsibility.

Expounding on the above paragraph and how it applies to my article: the act of calling AnimalFactory::CreateAnimal attempts to imply simply by naming convention, that a new object is being created. Furthermore, the fact the return value is a pointer to that object and not some handle, index, or alias, also intends to imply that the ownership of the resulting instance is being passed to the caller. It is a factory, not a pool or collection of any sort. Its only job is to create, simply by name, instances of implementation classes which derive from an abstract/interface class so that the caller need not know about any implementation details; it is forced to interact with the interface class and nothing else. That is assuming the caller does not cast the result to its "best guess" of what the implementation class is. In that case it immediately creates strongly-coupled code that can become fragile and difficult to maintain should the implementation class change.

Alright, time to wrap up this small novel... I hope that helps you and any other readers, understand this article's intent and purpose.

PS. Your "fix" for the "bug" you found does not compile. You might want to take a second look at the AnimalFactory::FactoryMap type definition, taking note of the second template parameter--it is a pointer to a function, not an object.
SuggestionRe: Bad code design. Pin
pasztorpisti16-Sep-12 2:33
pasztorpisti16-Sep-12 2:33 
GeneralRe: Bad code design. Pin
Cale Dunlap16-Sep-12 5:05
Cale Dunlap16-Sep-12 5:05 
GeneralRe: Bad code design. Pin
pasztorpisti16-Sep-12 6:30
pasztorpisti16-Sep-12 6:30 

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

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