|
|
EncapsulationTable of contentsNo headersEncapsulation is a term used in object oriented programming (e.g. C++, Java) to indicate that data and algorithms are separated in a computer program. This can be enforced in C as well, and we recommend that all new code is made according to the following standard:
To make this somewhat more tangible here is an example, of an algorithm to harvest apples from a tree. /* gmx_apple.h */ /* Abstract type defines a pointer to a structure */ typedef gmx_apple * gmx_apple_t; /* Initiate the orchard. This routine takes a pointer to an abstract, uninitialized, apple * datatype (which internally is a pointer-to-a-pointer, but that is none of the users business!), * and tries to initialize it, e.g. by allocating memory and settings stuff in the contents. * The return value tells us if the initialization was successful (0), or if something happened. * By using the return value for an error code rather than the data type we can check what went wrong. */ int gmx_apple_init(gmx_apple_t *apple); /* Get the harvest in kilograms for this year. Return 0 if OK, error code in case of problems */ int gmx_apple_get_harvest(gmx_apple_t apple,double *harvest); /* Set the amount of precipitation (mm/year). Return 0 if OK, error code otherwise */ int gmx_apple_set_precipitation(gmx_apple_t apple,double precipitation); /* Obliterate the orchard. Typically destructors do not return anything since we cannot do much * when/if they fail (what if the contents was partially destructed?). */ int gmx_apple_done(gmx_apple_t apple); A test program would look like this:
/* gmx_apple_test.c */
#include <stdio.h>
#include "gmx_apple.h"
int main(int argc,char *argv[])
{
gmx_apple_t apple;
double harvest;
int rc;
rc = gmx_apple_init(&apple);
/* handy trick - put constants first in comparisons! if you make a typo and turn this
* into an assignment, the compiler won't accept assigning to a constant value.
* Second, it is better to have short if-statements with a separate return statement
* rather than a huge if-statement spanning dozens of lines and increasing indentation.
*/
if( 0 != rc )
{
printf("No orchard could be established on this barren soil.\n");
return rc;
}
/* Note that we have hard-coded the precipation level for this year. 3 points deducted. */
rc = gmx_apple_set_precipitation(apple,130.5);
if ( 0 == rc )
{
rc = gmx_apple_get_harvest(apple,&harvest);
}
if ( 0 != rc )
{
printf("A storm prevent harvesting the otherwise healthy tree. Error code was %d\n",code);
}
else
{
printf("The harvest was %lf kg of juicy apples this year\n",harvest);
}
rc = gmx_apple_done(apple);
if ( 0 != rc )
{
printf("Can not even get rid of the orchard. Error code was %d\",rc);
}
return 0;
}
Finally, the implementation of gmx_apple.c is left as an exercise to the reader. Since we have a good API, who cares about the implementation? And, more important, next year when we plan to have our SSE-optimized orchard ready all routines using this API will magically see an amazing increase in apple harvest! |