
- •Introduction
- •Saving Time with This Book
- •Conventions Used in This Book
- •Part II: Working with the Pre-Processor
- •Part III: Types
- •Part IV: Classes
- •Part V: Arrays and Templates
- •Part VI: Input and Output
- •Part VII: Using the Built-in Functionality
- •Part VIII: Utilities
- •Part IX: Debugging C++ Applications
- •Part X: The Scary (or Fun!) Stuff
- •Icons Used in This Book
- •Creating and Implementing an Encapsulated Class
- •Creating a Mailing-List Application
- •Testing the Mailing-List Application
- •Customizing a Class with Polymorphism
- •Testing the Virtual Function Code
- •Why Do the Destructors Work?
- •Delayed Construction
- •The cDate Class
- •Testing the cDate Class
- •Creating the Header File
- •Testing the Header File
- •The Assert Problem
- •Fixing the Assert Problem
- •Using the const Construct
- •Identifying the Errors
- •Fixing the Errors
- •Fixing What Went Wrong with the Macro
- •Using Macros Appropriately
- •Using the sizeof Function
- •Evaluating the Results
- •Using sizeof with Pointers
- •Implementing the Range Class
- •Testing the Range Class
- •Creating the Matrix Class
- •Matrix Operations
- •Multiplying a Matrix by a Scalar Value
- •Multiplying a Matrix by Scalar Values, Take 2
- •Testing the Matrix Class
- •Implementing the Enumeration Class
- •Testing the Enumeration Class
- •Implementing Structures
- •Interpreting the Output
- •Defining Constants
- •Testing the Constant Application
- •Using the const Keyword
- •Illustrating Scope
- •Interpreting the Output
- •Using Casts
- •Addressing the Compiler Problems
- •Testing the Changes
- •Implementing Member-Function Pointers
- •Updating Your Code with Member-Function Pointers
- •Testing the Member Pointer Code
- •Customizing Functions We Wrote Ourselves
- •Testing the Default Code
- •Fixing the Problem
- •Testing the Complete Class
- •Implementing Virtual Inheritance
- •Correcting the Code
- •Rules for Creating Overloaded Operators
- •Using Conversion Operators
- •Using Overloaded Operators
- •Testing the MyString Class
- •Rules for Implementing new and delete Handlers
- •Overloading new and delete Handlers
- •Testing the Memory Allocation Tracker
- •Implementing Properties
- •Testing the Property Class
- •Implementing Data Validation with Classes
- •Testing Your SSN Validator Class
- •Creating the Date Class
- •Testing the Date Class
- •Some Final Thoughts on the Date Class
- •Creating a Factory Class
- •Testing the Factory
- •Enhancing the Manager Class
- •Implementing Mix-In Classes
- •Testing the Template Classes
- •Implementing Function Templates
- •Creating Method Templates
- •Using the Vector Class
- •Creating the String Array Class
- •Working with Vector Algorithms
- •Creating an Array of Heterogeneous Objects
- •Creating the Column Class
- •Creating the Row Class
- •Creating the Spreadsheet Class
- •Testing Your Spreadsheet
- •Working with Streams
- •Testing the File-Reading Code
- •Creating the Test File
- •Reading Delimited Files
- •Testing the Code
- •Creating the XML Writer
- •Testing the XML Writer
- •Creating the Configuration-File Class
- •Setting Up Your Test File
- •Building the Language Files
- •Creating an Input Text File
- •Reading the International File
- •Testing the String Reader
- •Creating a Translator Class
- •Testing the Translator Class
- •Creating a Virtual File Class
- •Testing the Virtual File Class
- •Using the auto_ptr Class
- •Creating a Memory Safe Buffer Class
- •Throwing and Logging Exceptions
- •Dealing with Unhandled Exceptions
- •Re-throwing Exceptions
- •Creating the Wildcard Matching Class
- •Testing the Wildcard Matching Class
- •Creating the URL Codec Class
- •Testing the URL Codec Class
- •Testing the Rot13 Algorithm
- •Testing the XOR Algorithm
- •Implementing the transform Function to Convert Strings
- •Testing the String Conversions
- •Implementing the Serialization Interface
- •Creating the Buffer Class
- •Testing the Buffer Class
- •Creating the Multiple-Search-Path Class
- •Testing the Multiple-Search-Path Class
- •Testing the Flow Trace System
- •The assert Macro
- •Logging
- •Testing the Logger Class
- •Design by Contract
- •Adding Logging to the Application
- •Making Functions Inline
- •Avoiding Temporary Objects
- •Passing Objects by Reference
- •Choosing Initialization Instead of Assignment
- •Learning How Code Operates
- •Testing the Properties Class
- •Creating the Locking Mechanism
- •Testing the Locking Mechanism
- •Testing the File-Guardian Class
- •Implementing the Complex Class
- •Creating the Conversion Code
- •Testing the Conversion Code
- •A Sample Program
- •Componentizing
- •Restructuring
- •Specialization
- •Index

Creating a Factory Class 163
Creating a Factory Class
The first step toward managing and processing objects is to create a factory class that works with a generic base class. The following steps show you how to create such a class that utilizes virtual methods to create, add, and delete objects. In this case, we create a base class called Object from which all of our managed objects will be derived.
1. In the code editor of your choice, create a new file to hold the code for the implementation of the factory code.
In this example, the file is named ch28.cpp, although you can use whatever you choose.
2. Type the code from Listing 28-1 into your file.
Better yet, copy the source file from this book’s companion Web site and change the names of the constants and variables as you choose.
LISTING 28-1: THE BASE-CLASS SOURCE CODE
#include <stdio.h> #include <string> #include <vector>
class Object
{
private:
std::string _name; bool _inUse;
public:
Object(void)
{
_name = “Object”; _inUse = false;
}
Object( const char *name )
{
_name = name; _inUse = false;
}
Object( const Object& aCopy )
{
_name = aCopy._name; _inUse = aCopy._inUse;
}
virtual ~Object()
{
}
virtual void MarkInUse( bool bFlag )
{
_inUse = bFlag;
}
virtual bool InUse( void )
{
return _inUse;
}
(continued)

164 Technique 28: Overriding Functionality with Virtual Methods
LISTING 28-1 (continued)
virtual const char *Name(void)
{
return _name.c_str();
}
virtual void Report() = 0;
};
class MyObject1 : public Object
{
public:
MyObject1()
: Object (“MyObject1”)
{
}
virtual void Report()
{
printf(“I am a MyObject1 Object\n”);
}
};
class MyObject2 : public Object
{
public:
MyObject2()
: Object (“MyObject2”)
{
}
virtual void Report()
{
printf(“I am a MyObject2 Object\n”);
}
};
class MyObject3 : public Object
{
public:
MyObject3()
: Object (“MyObject3”)
{
}
virtual void Report()
{
printf(“I am a MyObject3 Object\n”);
}
};
class Factory
{
private:
std::vector< Object *> _objects;

Creating a Factory Class 165
public:
Factory()
{
}
// Method to add an object to the pool virtual void Add( Object *obj )
{
obj->MarkInUse( true ); _objects.insert( _objects.end(), obj );
}
// Method to retrieve an object not in use virtual Object *Get( void )
{
std::vector< Object *>::iterator iter;
for ( iter = _objects.begin(); iter != _objects.end(); ++iter )
{
if ( (*iter)->InUse() == false )
{
printf(“Found one\n”);
// Mark it in use (*iter)->MarkInUse( true ); // And give it back
return (*iter);
}
}
// Didn’t find one. return NULL;
}
virtual void Remove( Object *obj )
{
std::vector< Object *>::iterator iter;
for |
( iter = _objects.begin(); iter != _objects.end(); ++iter ) |
|
|
{ |
if ( (*iter) == obj ) |
|
|
|
|
|
|
|
{ |
|
|
|
(*iter)->MarkInUse( false ); |
|
|
|
break; |
|
|
} |
} |
|
|
|
|
|
|
} |
|
|
|
virtual |
void Report() |
|
1 |
{ |
|
|
std::vector< Object *>::iterator iter;
(continued)

166 Technique 28: Overriding Functionality with Virtual Methods
LISTING 28-1 (continued)
for ( iter = _objects.begin(); iter != _objects.end(); ++iter )
{
if ( (*iter)->InUse() == true )
{
printf(“Object at %lx in use\n”, (*iter) );
}
else
{
printf(“Object at %lx NOT in use\n”, (*iter) );
}
(*iter)->Report();
}
}
};
3. Save the file to disk and close the code editor.
4. Compile the application on the operating system of your choice, using your chosen compiler.
Always implement a method that can report on the state of an object of each class. This allows you to do quick memory dumps at any time, via the factory for each base class. This class can be used by a factory class to report status, and can be overridden via virtual methods to extend that status reporting for derived classes.
Testing the Factory
After you create a class, you should create a test driver that not only ensures that your code is correct, but also shows people how to use your code. The following steps show you how to create a simple test driver to illustrate how the factory class interacts with the derived objects via virtual methods.
1. In the code editor of your choice, open the source file to hold the code for the test driver.
In this example, the file is named ch28.cpp, although you can use whatever you choose.
2. Type the code from Listing 28-2 into your file.
Better yet, copy the code from the source file on this book’s companion Web site and change the names of the constants and variables as you choose.
LISTING 28-2: THE TEST DRIVER FOR THE FACTORY OBJECT
int main()
{
//Implement an object factory object Factory f;
//Add some objects to the factory MyObject1 *obj1 = new MyObject1; MyObject2 *obj2 = new MyObject2; MyObject3 *obj3 = new MyObject3;
f.Add( obj1 ); f.Add( obj2 ); f.Add( obj3 );
//Remove one to simulate the destruction of an object
f.Remove( obj1 );
//Now try to get a new one back. Object *pObject = f.Get(); printf(“I got back a %s object\n”,
pObject->Name() );