OO Tips For The C Programmer Part II
Note: This article was published originally in the Cap Gemini America - Cincinnati Unit Newsletter. Introduction This is the second article in a series on Object Oriented programming techniques using 'C'. In the previous installment of this series of articles I explained how to use 'C' to define a class. The DISTANCE class was used as an example. In this installment encapsulation will be presented including how to define public and private members of a class. Encapsulation is the ability to hide the internal implementation details of an object from the outside world. Basic Concepts This section provides a brief explanation of some 'C' constructs that will be used later to support encapsulation. Static Functions A static function is a function that is only visible in the file that contains it. A static function is defined by adding the wordstatic at the beginning of the function definition. For example, if we have a file called test1.c that has the function: static int square(int x) { return x*x; } then the only functions that can use square() are functions defined in the file test1.c Casting Casting provides the ability to convert a value to a different type. To cast an expression, put the target data type in parentheses directly before the expression. For example: float x; x= (float) 1; assigns the int value 1 to the float variable x. In the previous installment we used casting in the constructor: DISTANCE* ob=(DISTANCE*) calloc(1, sizeof(DISTANCE)); The calloc() function returns a void pointer, and we cast it to DISTANCE pointer in order to assign this value to ob without the compiler generating any warning messages. In summary, if we have the cast: (MyType)MyValue we will be telling the compiler to treat MyValue as if it is of type MyType. Encapsulation We need to have a facility in which the methods of a class can only be accessed through the class. Additionally, the class may have members that should not be visible outside the class definition, i.e. private. Methods Scope For a class, only its definition should be visible by the class' users. The implementation of the class should be completely hidden. The solution is simple:
For our DISTANCE class, put the class definition (i.e. struct) in distance.h, put the implementation of its methods in distance.c and make all the methods static (except ConstructDistance). For example: static float DistanceKm(DISTANCE* this) { return this->DistanceMiles*1.609; } Private Members Although the class implementation is hidden from its users, all the class members are accessible by anyone who uses this class. We need to have a mechanism in which some of the class's members are inaccessible by the class users. In our DISTANCE class, suppose we want to be able to setand get the distance in both units of Miles or Kilometer.
typedef struct { float DistanceMiles; } PrivateType;
ob->private= calloc(1, sizeof(PrivateType));
free((*this)->private);
static void SetMiles(DISTANCE* this, float miles) { PrivateType* p= (PrivateType*)this->private; p->DistanceMiles= miles; }
Conclusion It is shown here that with utilizing some standard 'C' constructs we are capable of supporting encapsulation. This is achieved with a simple approach. Mainly, define all methods implementation to be static and have a class member that the user can not change (private). In the next installment of this series of articles, I will discuss inheritance and polymorphism then see if we could implement them using 'C'. Acknowledgment I would like to thank both of Carol Viera and Srinivasa Komatineni for their review and suggestions. References
|