In my own project I would have an additional requirement:
My specific classes have some functionality, which is common to all specific classes.
So I thought, I could create a further base class to implement common stuff. I do not want to implement same code to several specific classes.
Example:
In the interface class IAnimal I added
virtual void Common_NrOfHeads() = 0;
This function would be same for each animal and return just 1.
So I thought, I could put such code to a common base class for all animals:
class Animal_Common < public: int Common_NrOfHeads() return 1;>; >; // IAnimal implementations class Cat : public IAnimal, public Animal_Common bholman 16-Sep-16 4:16Thanks!
Bill Holman
Bill Holman
Software Engineer
Video Gaming Technologies
Sr. Systems Programmer
bholman@bholman.com LastBlow1 28-Jul-16 22:05
Thank you for this post! How about if we want to count the total of instances of each derived class and number each instance of a given derived class, please? Also, how to declare a function Create with more than one parameter, such as shared_ptr Create(string name, glm::vec4 center, float dimension, glm::mat4 transform);? Thank you! | |
Sign in· View Thread |
A Good Article with very good discussions . that is why have My 5 points and Thanks to share. | |
Sign in· View Thread |
Is there any way of introducing a configuration file to register new animals with the objective of stopping violating the open close principle? | |
Sign in· View Thread |
Very nice explanation. | |
Sign in· View Thread |
Nicely implemented and explained !! | |
Sign in· View Thread |
Disclaimer: Now I’m not entirely sure how closely my model fits to the typical Factory pattern but as far as I understand the Factory pattern, it is pretty close if not exact.
There are two factory patterns I'm aware of. One of them is the factory method, and the other is the abstract factroy pattern. Your code is a specific implementation of the factory method, one which has a create parameter that is the type (name) of the creatable object. Your factory class could be the inner implementation of the following factory method:
static IAnimal* IAnimal::Create(const string &animalName);Espen Harlinn 16-Sep-12 1:22
Imagine you are writing a C++ user interface library for Windows implementing classes for the various controls available with the OS. Perhaps you would end up with a class hierarchy looking somewhat like this:
Control TextBaseControl TextControl NumericControl DateTimeControl ItemsControl ListBoxControl ListViewControl Form
Now, in the Control constructor, you want to create the handle for the window - Since you can't rely on a virtual function to provide you with a handle of the correct type, you might do something like this:
Control::Control(ControlFactory* factory) < handle = factory->CreateHandle(); >
A hierarchy of factory classes would then perhaps look like this:
ControlFactory TextBaseControlFactory TextControlFactory NumericControlFactory DateTimeControlFactory ItemsControlFactory ListBoxControlFactory ListViewControlFactory FormFactory
Where the various classes are responsible for creating a handle of the correct type.
So, yes, the factory pattern is particularly important to C++ programmers.
Espen Harlinn
Principal Architect, Software - Goodtech Projects & Services AS
Projects promoting programming in "natural language" are intrinsically doomed to fail. Edsger W.Dijkstra
IAnimal *AnimalFactory::CreateAnimal(const string &animalName) < FactoryMap::iterator it = m_FactoryMap.find(animalName); if( it != m_FactoryMap.end() ) return it->second()->Create();Steve Giancarlo 15-Sep-12 6:50 Cale Dunlap 15-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.
pasztorpisti 16-Sep-12 2:33The original post with its 3 points just make no sense here. However you said something that simply isn't true:
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).
Cale Dunlap 16-Sep-12 5:05Your points are valid, and I agree with you. They do make code a bit easier to maintain and prevent unnecessary memory leaks. I'm not arguing against the use of reference counting, auto pointers, or the sort. My point, though somewhat of a generalization, was to say that not all bodies of code make extensive use of such mechanisms.