I am considering realizing a simple interface pattern in the C language.
A key characteristic is that it would provide multiple definitions for an opaque sturcture supplied by the interface's public header, that is, different implementations would provide different underlaying data for that structure (so across different translation units, the same structure would have different implementation).
I couldn't find any reference whether this would be a good or bad design pattern. At least it doesn't seem to violate the strict aliasing rule, only relying on the consistent order and padding for the common first element(s), which is guaranteed by the C standard (as far as I see). Of course I am aware of opject oriented patterns in C, but I couldn't see this particular one used.
Is this acceptable? Was such a pattern even used? (I couldn't find anything)
For easing understanding, following is a working example of three source files:
reader.h (The public interface definition)
#ifndef READER_H
#define READER_H
typedef struct reader_s reader_t;
char reader_read(reader_t* r);
#endif
reader.c (Glue logic for the interface)
#include "reader.h"
typedef char (reader_f)(reader_t*);
struct reader_s{
reader_f* rfunc;
};
char reader_read(reader_t* r)
{
return r->rfunc(r);
}
reader1.h (An implementation of the interface, header)
#ifndef READER1_H
#define READER1_H
#include "reader.h"
reader_t* reader1_get(void);
#endif
reader1.c (An implementation of the interface, code)
#include "reader1.h"
typedef char (reader_f)(reader_t*);
struct reader_s{
reader_f* rfunc;
int pos;
};
static char reader1_read(reader_t* r);
reader_t reader1_obj = {&reader1_read, 0};
reader_t* reader1_get(void)
{
return &reader1_obj;
}
static char reader1_read(reader_t* r)
{
char rval = 'A' + (r->pos);
(r->pos) = (r->pos) + 1;
if ((r->pos) == 24){ (r->pos) = 0; }
return rval;
}
main.c (Example usage)
#include "reader1.h"
#include <stdio.h>
int main(void)
{
reader_t* rd = reader1_get();
int i;
printf("\n");
for (i = 0; i < 60; i++){
printf("%c", reader_read(rd));
}
printf("\n");
return 0;
}
Possibly the interface should provide another header file for implementers, providing the definition of the structure head containing the function pointers. Maybe it could even rather point to a class structure containing those to minimize object sizes for classes with many methods.