Abstract type: Difference between revisions

Content added Content deleted
(Start addition of C)
(→‎{{header|C}}: add substance)
Line 49: Line 49:


=={{header|C}}==
=={{header|C}}==
Doing abstract types in C is not particularly trivial as C doesn't really support classes. The following series will show an abstract type, followed by a realizable class that provides the abstract interface, and finally followed by an exampleof usage.
Doing abstract types in C is not particularly trivial as C doesn't really support classes. The following series will show an abstract type, followed by a realizable class that provides the abstract interface, and finally followed by an example of usage.

The header file for the abstract class, interfaceAbs.h
<lang c>#ifndef INTERFACE_ABS
#define INTERFACE_ABS

typedef struct sAbstractCls *AbsCls;

typedef struct sAbstractMethods {
int (*method1)(AbsCls c, int a);
char *(*method2)(AbsCls c, int b);
void (*method3)(AbsCls c, double d);
} *AbstractMethods, sAbsMethods;

struct sAbstractCls {
AbstractMethods klass;
void *instData;
};

#define ABSTRACT_METHODS( cName, m1, m2, m3 ) \
static sAbsMethods cName ## _Iface = { &m1, &m2, &m3 }; \
AbsCls cName ## _Instance( void *clInst) { \
AbsCls ac = (AbsCls)malloc(sizeof(struct sAbstractCls)); \
if (ac) { \
ac->klass = &cName ## _Iface; \
ac->instData = clInst; \
}\
return ac; }

#define Abs_Method1( c, a) c->klass->method1(c, a)
#define Abs_Method2( c, b) c->klass->method2(c, b)
#define Abs_Method3( c, d) c->klass->method3(c, d)
#define Abs_Free(c) \
do { if(c && c->instData) free(c->instData); if (c) free(c); } while(0);
#endif</lang>
That will define the abstract class. The next section declares a public interface for a class providing the interface of the abstract class. This class is Silly and
the code is in file silly.h. Note the actual structure of the class is not provided
here. We don't want it visible.
<lang c>#ifndef SILLY_H
#define SILLY_H
#include intefaceAbs.h

typedef struct sillyStruct *Silly;
extern Silly NewSilly( double, char *);
extern AbsCls Silly_Instance(void *);

#endif</lang>
Ok. Now it is necessary to provide the implementation of the realizable class.
This code should be in silly.c.
<lang c>#include "silly.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

struct sillyStruct {
double v1;
char str[32];
};

Silly NewSilly(double vInit, char *strInit)
{
Silly sily = (Silly)malloc(sizeof( struct sillyStruct ));
sily->v1 = vInit;
strncpy(sily->str, strInit, 30);
return sily;
}

static
int MyMethod1( AbsCls c, int a)
{
Silly s = (Silly)(c->instData);
return a+strlen(s->str);
}

static
char *MyMethod2(AbsCls c, int b)
{
Silly s = (Silly)(c->instData);
sprintf(s->str, "%d", b);
return s->str;
}

static
void MyMethod3(AbsCls c, double d)
{
Silly s = (Silly)(c->instData);
printf("InMyMethod3, %f\n",s->v1 * d);
}

ABSTRACT_METHODS( Silly, MyMethod1, MyMethod2, MyMethod3)</lang>
That last macro, ABSTRACT_METHODS may need a little explanation. First note that macros do a string substitution of the parameter values into the arguments of the defined macro, with a little hitch. In the macro definition the ' ## ' expression is special. Here cName ## _Iface gets converted to Silly_Iface, as 'Silly' replaces cName. So the macro call declares an instance of the class record, and defines a constructor named Silly_Instance, which takes a Silly structure as an arguments
and uses the class record it previously set up as well.

The methods MyMethod1, MyMethod2, and MyMethod3 are called through the abstract class interface and do not need to be visible outside this file. Hence, they are declared static.

Now all's left is some example code that uses all this stuff.
<lang c>#include <stdio.h>
#include "silly.h"

int main(int argc, char *argv[])
{
AbsCls abster = Silly_Instance(NewSilly( 10.1, "Green Tomato"));

printf("AbsMethod1: %d\n", Abs_Method1(abster, 5));
printf("AbsMethod2: %s\n", Abs_Method2(abster, 4));
Abs_Method3(abster, 21.55);
Abs_Free(abster);
return 0;
}
</lang>


=={{header|C#}}==
=={{header|C#}}==