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 |
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#}}== |