This series is for those who have decided the quirks of C++ classes are more trouble than they are worth. I intend to provide alternatives to certain features of classes that can be emulated using more traditional techniques. This article is not meant to be argumental, so I will not go into the 'why' of avoiding classes, rather I will assume you've read one of the many papers out there pointing out its many flaws and you've decided you would like to use them as little as possible. The format of this series will likely resemble that of this article; first bringing up a feature of classes that we can emulate, then going into the implementation, followed by any limitations of the approach.
[size="5"]Object Instances
I once read that class based programming provides an advantage over ordinary modular programming in that the former allows multiple instances of objects that are completely independent of each other, while the latter doesn't have that support. Such blasphemy is the topic of this, the first article of the series. To begin, let's take a look at a simple class:
// let's say this is in c_example.h
class C_Example
{
public:
void Displayxy( void );
void Setx( int xValue );
void Sety( int yValue );
private:
int x;
int y;
};
// and this is in c_example.cpp
#include "c_example.h"
void C_Example::Displayxy( void )
{
cout << "x == " << x << '\n' << "y == " << y << '\n';
}
void C_Example::Setx( int xValue )
{
x = xValue;
}
void C_Example::Sety( int yValue )
{
y = yValue;
}
#include "c_example.h"
void main( void )
{
// create two instances of C_Example
C_Example inst1;
C_Example inst2;
// set x and y for the first instance
inst1.Setx( 5 );
inst1.Sety( 4 );
// set x and y for the second instance
inst2.Setx( 8 );
inst2.Sety( 9 );
// display contents of each
inst1.Displayxy();
inst2.Displayxy();
}
// this might be in m_example.h
void Example_Displayxy( void );
void Example_Setx( int xValue );
void Example_Sety( int yValue );
// and this might be in m_example.cpp
#include "m_example.h"
static int _x;
static int _y;
void Example_Displayxy( void )
{
cout << "x == " << _x << '\n' << "y == " << _y << '\n';
}
void Example_Setx( int xValue )
{
_x = xValue;
}
void Example_Sety( int yValue )
{
_y = yValue;
}
// now to use the module:
#include "m_example.h"
void main( void )
{
// you cannot declare multiple instances with this approach.
// there is only one instance, which is the content of "m_example.cpp".
Example_Setx( 5 );
Example_Sety( 4 );
Example_Displayxy();
}// this might be in m_example.h
void Example_Displayxy( void );
void Example_Setx( int xValue );
void Example_Sety( int yValue );
// and this might be in m_example.cpp
#include "m_example.h"
static int _x;
static int _y;
void Example_Displayxy( void )
{
cout << "x == " << _x << '\n' << "y == " << _y << '\n';
}
void Example_Setx( int xValue )
{
_x = xValue;
}
void Example_Sety( int yValue )
{
_y = yValue;
}
// now to use the module:
#include "m_example.h"
void main( void )
{
// you cannot declare multiple instances with this approach.
// there is only one instance, which is the content of "m_example.cpp".
Example_Setx( 5 );
Example_Sety( 4 );
Example_Displayxy();
}
// the new "m_example.h"
// the m_example data type
typedef unsigned int M_Example;
// module interface functions
M_Example Example_CreateInstance( void );
void Example_Displayxy( M_Example objInst );
void Example_Setx( M_Example objInst, int xValue );
void Example_Sety( M_Example objInst, int yValue );
// the new "m_example.cpp"
#include "m_example.h"
#define _MAXOBJECTS 128
struct _PRIVATE
{
int x;
int y;
}static _private[ _MAXOBJECTS];
M_Example _curInstance = 0;
M_Example Example_CreateInstance( void )
{
_curInstance++;
return( _curInstance - 1 );
}
void Example_Displayxy( M_Example objInst )
{
cout << "x == " << _private[objInst].x << '\n' << "y == " << _private[objInst].y << '\n';
}
void Example_Setx( M_Example objInst, int xValue )
{
_private[objInst].x = xValue;
}
void Example_Sety( M_Example objInst, int yValue )
{
_private[objInst].y = yValue;
}
// and to use the new module:
#include "m_example.h"
void main( void )
{
// with the new module you can create more than one instance:
// create two instances of M_Example
M_Example inst1 = Example_CreateInstance();
M_Example inst2 = Example_CreateInstance();
// set x and y for the first instance
Example_Setx( inst1, 5 );
Example_Sety( inst1, 4 );
// then set x and y for the second instance
Example_Setx( inst2, 8 );
Example_Sety( inst2, 9 );
// display the contents of both
Example_Displayxy( inst1 );
Example_Displayxy( inst2 );
}
[size="5"]In Conclusion: The Good And The Bad
As you can see, multiple instances of a module are possible despite what some will have you believe. Using this method, an array of a structure entitled _private takes the place of the private keyword, and in this case it actually is private, not sitting in the interface file for everyone to see like in the case of a class definition. The datatype M_Example is really just an int as an ID to be used as an index to the _private array. When you create an object using Example_CreateInstance, you're just reserving a spot in that array. You'll immediately notice two flaws to this approach I'm sure. First, the number of objects is limited to _MAXOBJECTS. Also, you can create an object, but you apparently can't destroy it. Well, that's where a linked list would come in handy. I only used an array to keep the idea clear, but if you were to use this method, using a linked list is the only way to go. Well, that's it for this article. Any questions, comments, flames, or new article ideas can be directed to godofarson@aol.com. Hopefully this article has sparked some ideas for you, if so let me know.