I suggest you learn them too, Ian. Because you seem to be mixing up the
Factory pattern with the State pattern. You're mixing up pre-allocating
memory (or using a small-block/fixed-block memory allocator with placement
new) with pre-instantiating objects. You don't even know that all classes
which are derived from SHOULD ALWAYS have a virtual destructor - and you
don't seem to know that not having that leaves deeply embedded bugs and
indicates very sloppy programming.
Which means that your learnin' is sloppy, boy.
May I recommend reading Design Patterns by the GOF, and all of Scott
Meyers' books? It would appear that you need a refresher at least.
You can only make the statement that base classes have virtual destructors
if they have no state themselves. Have a look at this class and tell me if
there is the need for a virtual destructor or not.
/**START[HeaderBlock]-----------------------------------------------------
*
* Filename: HSocket.cpp
*
* Last Modified date:
* Tuesday, 19 September 2000
* Author :
* Ian Hilliard
*
* Description:
* General purpose socket class for connection oriented and conectionless
* operation. This class is also intended for use with HSocketPool for
* managing multiple sockets within a single thread.
*
*END[HeaderBlock]---------------------------------------------------------
*/
#include "StdAfx.h"
//*START[ApplicationIncludes]---------------------------------------------
#include "HSocket.h"
//*END[ApplicationIncludes]-----------------------------------------------
//*START[StaticDefinitions]-----------------------------------------------
//*END[StaticDefinitions]-------------------------------------------------
/**-----------------------------------------------------------------------
* Operation: Default Constructor
* Create an instance of HSocket where the backlog is specified. If *
backlog is not specified, a default value of 8 is used.
*-------------------------------------------------------------------------
* Parameters:
* int backLog
* The number of connections that can be accepted without being serviced.
*-------------------------------------------------------------------------
* Returns:
* void
*-------------------------------------------------------------------------
*/
HSocket::HSocket( int backLog )
: m_backlog( backLog ),
m_initialised( false )
{
// Initialise Winsock to use version 2.2. if( WSAStartup( MAKEWORD( 2, 2
), & m_wsa ) != 0 ) {
m_exception.addEntry( (int) sockerr_wsaStartup, WSAGetLastError() );
throw m_exception;
}
}
//*END[Operation]---------------------------------------------------------
/**-----------------------------------------------------------------------
* Operation: ~HSocket
* Default Destructor
*-------------------------------------------------------------------------
*/
HSocket::~HSocket( )
{
closesocket( m_socket );
WSACleanup();
}
//*END[Operation]---------------------------------------------------------
If HSocket had a vitrual destructor, then it would be necessary for each
child to do it's own clean up. And as the saying goes; "Children are
not permitted to play with their parent's privates."
There are also other problems with virtual destructors. It looks like
you're another one of those programmers who read Meyers and now thinks he
can program. The important thing with programming is understanding what
it is that the compiler is doing with the code.
As far as preallocating goes, best practice demands that the objects be
preallocated and then initialized as required. I suggest that you read
"Advanced C++ Programming Styles and Idioms" by James O. Coplien.
As far as returning const references, that is very simple
const State & MyClass::getState( Event transitionEvent,
const State & previousState )
{
switch( transitionEvent )
{
case pouring:
m_milkState.setState( previousState );
return( m_milkState );
case curdling:
m_curdsState.setState( previousState );
return( m_curdsState );
case separating:
m_cheeseState.setState( previousState );
return( m_cheeseState ):
case churning:
m_butterState.setState( previousState );
return( m_butterState );
default:
return( m_unknownState );
}
}
Using this pattern, you get a new set of functionality based on the new
state. The new state is set to reflect the previous state. Each of these
state objects provides state functionality with the only possible changes
to their state being made by the state factory. This is a very efficient
variant on the state pattern.
It should be noted that the entry point of each state is the same virtual
method call. Hence, the calling class can simply use the returned reference
and make the same method call.
Ian