Modular Programming: A Classless Approach Part I
by Dan Arson

Who is this written for?

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.

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 independant 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; }

Now, declaring and using multiple instances might be done something like:

#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(); }

I'd like to point out here that while this example is extremely stupid and useless, I'm using it to make sure the ideas being discussed get through without any distractions. Now, on to the standard modular version:

// 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(); }

Now for the fun part. The example above clearly shows the reason why most people assume the only way to support multiple instances of an object is through classes. The alternate approach I'm going to give here uses an array to hold member data.

// 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 ); }

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.

Discuss this article in the forums


Date this article was posted to GameDev.net: 6/24/2000
(Note that this date does not necessarily correspond to the date the article was written)

See Also:
General

© 1999-2011 Gamedev.net. All rights reserved. Terms of Use Privacy Policy
Comments? Questions? Feedback? Click here!