Skip to content

Instantly share code, notes, and snippets.

@be9
Created November 6, 2012 03:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save be9/4022385 to your computer and use it in GitHub Desktop.
Save be9/4022385 to your computer and use it in GitHub Desktop.

Объектная система с метаклассами

Компиляция

Все C-файлы компилируются в консольное приложение.

Возможна проблема с макроопределением CLONE_VA_LIST из Object_internal.h. Если компилятор не поддерживает стандарт C99, попробуйте воспользоваться вторым вариантом макро, который закомментирован.

Запуск

Вызывать главную программу: circles p c c p c p.

Каждая p будет приводить к созданию объекта класса Point, c – объекта класса Circle. Затем на созданный объект будет вызвана виртуальная функция draw(), статическая функция move() и затем снова draw().

Оба класса Point и Circle являются инстансами метакласса PointClass. PointClass унаследован от Class (базового метакласса), добавляя к нему указатель на виртуальную функцию draw().

#include <stdio.h>
#include "Circle.h"
#include "Circle_internal.h"
static void *Circle_ctor(void *_self, va_list *app)
{
struct Circle * self = super_ctor(Circle, _self, app);
self->rad = va_arg(*app, int);
return self;
}
static void Circle_draw(const void * _self)
{
const struct Circle *self = _self;
printf("circle at %d,%d rad %d\n",
x(self), y(self), self->rad);
}
/*
* initialization
*/
const void *Circle;
void initCircle(void)
{
if (!Circle)
{
initPoint();
Circle = new(PointClass, "Circle",
Point, sizeof(struct Circle),
ctor, Circle_ctor,
draw, Circle_draw,
0);
}
}
#ifndef CIRCLE_H
#define CIRCLE_H
#include "Point.h"
extern const void *Circle; /* new(Circle, x, y, rad) */
void initCircle(void);
#endif
#ifndef CIRCLE_INTERNAL_H
#define CIRCLE_INTERNAL_H
#include "Point_internal.h"
struct Circle { const struct Point _; int rad; };
#endif
#include "Circle.h"
int main (int argc, char **argv)
{
void * p;
initCircle();
while (*++argv)
{
switch (** argv) {
case 'c':
p = new(Circle, 1, 2, 3);
break;
case 'p':
p = new(Point, 1, 2);
break;
default:
continue;
}
draw(p);
move(p, 10, 20);
draw(p);
delete(p);
}
return 0;
}
project(sos2)
add_executable(circles circles.c Circle.c Object.c Point.c)
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "Object.h"
#include "Object_internal.h"
/*
* Object
*/
static void *Object_ctor(void *_self, va_list *app)
{
return _self;
}
static void *Object_dtor(void *_self)
{
return _self;
}
static int Object_differ(const void *_self, const void *b)
{
return _self != b;
}
static int Object_puto(const void *_self, FILE *fp)
{
const struct Class * class = classOf(_self);
return fprintf(fp, "%s at %p\n", class->name, _self);
}
const void *classOf(const void *_self)
{
const struct Object * self = _self;
assert(self && self->class);
return self->class;
}
size_t sizeOf(const void *_self)
{
const struct Class *class = classOf(_self);
return class->size;
}
/*
* Class
*/
static void *Class_ctor(void *_self, va_list *app)
{
struct Class *self = _self;
const size_t offset = offsetof(struct Class, ctor);
self->name = va_arg(*app, char *);
self->super = va_arg(*app, struct Class *);
self->size = va_arg(*app, size_t);
assert(self->super);
memcpy((char *)self + offset, (char *)self->super
+ offset, sizeOf(self->super) - offset);
{
typedef void (*voidf)(); /* generic function pointer */
voidf selector;
CLONE_VA_LIST(ap, *app);
while ((selector = va_arg(ap, voidf)))
{
voidf method = va_arg(ap, voidf);
if (selector == (voidf)ctor)
*(voidf *)&self->ctor = method;
else if (selector == (voidf)dtor)
*(voidf *)&self->dtor = method;
else if (selector == (voidf)differ)
*(voidf *)&self->differ = method;
else if (selector == (voidf)puto)
*(voidf *)&self->puto = method;
}
return self;
}
}
static void *Class_dtor(void *_self)
{
struct Class *self = _self;
fprintf(stderr, "%s: cannot destroy class\n", self->name);
return 0;
}
const void *super (const void *_self)
{ const struct Class *self = _self;
assert(self && self->super);
return self->super;
}
/*
* initialization
*/
static const struct Class object[] = {
{
{ object + 1 },
"Object", object, sizeof(struct Object),
Object_ctor, Object_dtor, Object_differ, Object_puto
},
{
{ object + 1 },
"Class", object, sizeof(struct Class),
Class_ctor, Class_dtor, Object_differ, Object_puto
}
};
const void *Object = object;
const void *Class = object + 1;
/*
* object management and selectors
*/
void *new(const void *_class, ...)
{
const struct Class *class = _class;
struct Object *object;
va_list ap;
assert(class && class->size);
object = calloc(1, class->size);
assert(object);
object->class = class;
va_start(ap, _class);
object = ctor(object, & ap);
va_end(ap);
return object;
}
void delete (void *_self)
{
if (_self)
free(dtor(_self));
}
void *ctor(void *_self, va_list *app)
{
const struct Class * class = classOf(_self);
assert(class->ctor);
return class->ctor(_self, app);
}
void *super_ctor (const void *_class, void *_self, va_list * app)
{
const struct Class *superclass = super(_class);
assert(_self && superclass->ctor);
return superclass->ctor(_self, app);
}
void *dtor(void *_self)
{
const struct Class *class = classOf(_self);
assert(class->dtor);
return class->dtor(_self);
}
void *super_dtor(const void *_class, void *_self)
{
const struct Class *superclass = super(_class);
assert(_self && superclass->dtor);
return superclass->dtor(_self);
}
int differ(const void *_self, const void *b)
{
const struct Class *class = classOf(_self);
assert(class->differ);
return class->differ(_self, b);
}
int super_differ (const void *_class, const void *_self, const void *b)
{
const struct Class *superclass = super(_class);
assert(_self && superclass->differ);
return superclass->differ(_self, b);
}
int puto(const void *_self, FILE * fp)
{
const struct Class *class = classOf(_self);
assert(class->puto);
return class->puto(_self, fp);
}
int super_puto (const void *_class, const void *_self, FILE * fp)
{
const struct Class *superclass = super(_class);
assert(_self && superclass->puto);
return superclass->puto(_self, fp);
}
#ifndef OBJECT_H
#define OBJECT_H
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
extern const void *Object; /* new(Object); */
void *new(const void *class, ...);
void delete(void *self);
const void *classOf(const void *self);
size_t sizeOf(const void *self);
void *ctor(void *self, va_list *app);
void *dtor(void *self);
int differ(const void *self, const void *b);
int puto(const void *self, FILE *fp);
extern const void *Class; /* new(Class, "name", super, size
sel, meth, ... 0); */
const void *super(const void *self); /* class' superclass */
#endif
#ifndef OBJECT_INTERNAL_H
#define OBJECT_INTERNAL_H
struct Object {
const struct Class *class; /* object's description */
};
struct Class {
const struct Object _; /* class' description */
const char *name; /* class' name */
const struct Class* super; /* class' super class */
size_t size; /* class' object's size */
void *(*ctor)(void *self, va_list *app);
void *(*dtor)(void *self);
int (*differ)(const void *self, const void *b);
int (*puto)(const void *self, FILE *fp);
};
void *super_ctor(const void *class, void *self, va_list *app);
void *super_dtor(const void *class, void *self);
int super_differ(const void *class, const void *self, const void *b);
int super_puto(const void *class, const void *self, FILE *fp);
#define CLONE_VA_LIST(a,b) va_list a; va_copy(a, b)
/* #define CLONE_VA_LIST(a,b) va_list a = b */
#endif
#include <assert.h>
#include "Point.h"
#include "Point_internal.h"
/*
* Point
*/
static void *Point_ctor(void *_self, va_list *app)
{
struct Point *self = super_ctor(Point, _self, app);
self->x = va_arg(*app, int);
self->y = va_arg(*app, int);
return self;
}
static void Point_draw(const void *_self)
{
const struct Point *self = _self;
printf("\".\" at %d,%d\n", self->x, self->y);
}
void draw (const void *_self)
{
const struct PointClass *class = classOf(_self);
assert(class->draw);
class->draw(_self);
}
void super_draw(const void *_class, const void *_self)
{
const struct PointClass *superclass = super(_class);
assert(_self && superclass->draw);
superclass->draw(_self);
}
void move(void *_self, int dx, int dy)
{
struct Point *self = _self;
self->x += dx, self->y += dy;
}
/*
* PointClass
*/
static void *PointClass_ctor(void *_self, va_list *app)
{
struct PointClass *self
= super_ctor(PointClass, _self, app);
typedef void (* voidf)();
voidf selector;
CLONE_VA_LIST(ap, *app);
while ((selector = va_arg(ap, voidf)))
{
voidf method = va_arg(ap, voidf);
if (selector == (voidf)draw)
*(voidf *)&self->draw = method;
}
return self;
}
/*
* initialization
*/
const void *PointClass, *Point;
void initPoint(void)
{
if (!PointClass)
PointClass = new(Class, "PointClass",
Class, sizeof(struct PointClass),
ctor, PointClass_ctor,
0);
if (!Point)
Point = new(PointClass, "Point",
Object, sizeof(struct Point),
ctor, Point_ctor,
draw, Point_draw,
0);
}
#ifndef POINT_H
#define POINT_H
#include "Object.h"
extern const void *Point; /* new(Point, x, y); */
void draw(const void *self);
void move(void *point, int dx, int dy);
extern const void *PointClass; /* adds draw */
void initPoint(void);
#endif
#ifndef POINT_INTERNAL_H
#define POINT_INTERNAL_H
#include "Object_internal.h"
struct Point {
const struct Object _; /* Point : Object */
int x, y; /* coordinates */
};
#define x(p) (((const struct Point *)(p)) -> x)
#define y(p) (((const struct Point *)(p)) -> y)
void super_draw (const void *class, const void *self);
struct PointClass {
const struct Class _; /* PointClass : Class */
void (*draw)(const void * self);
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment