Чтобы иметь чистый код, может быть полезно использовать некоторые концепции объектно-ориентированного программирования, даже в C. Я часто пишу модули, состоящие из пары файлов .h и .c. Проблема в том, что пользователь модуля должен быть осторожен, так как закрытые члены не существуют в C. Использование идиомы pimpl или абстрактных типов данных допустимо, но это добавляет некоторый код и/или файлы и требует более тяжелый код. Я ненавижу использовать аксессуар, когда он мне не нужен.
Вот идея, которая позволяет заставить компилятор жаловаться на недопустимый доступ к закрытым членам с помощью всего лишь нескольких дополнительных кодов. Идея состоит в том, чтобы дважды определить одну и ту же структуру, но с некоторой дополнительной константой, добавленной для пользователя модуля.
Конечно, писать в приват еще можно с гипсом. Но дело только во избежание ошибок со стороны пользователя модуля, а не в надежной защите памяти.
/*** 2DPoint.h module interface ***/
#ifndef H_2D_POINT
#define H_2D_POINT
/* 2D_POINT_IMPL need to be defined in implementation files before #include */
#ifdef 2D_POINT_IMPL
#define _cst_
#else
#define _cst_ const
#endif
typedef struct 2DPoint
{
/* public members: read and write for user */
int x;
/* private members: read only for user */
_cst_ int y;
} 2DPoint;
2DPoint *new_2dPoint(void);
void delete_2dPoint(2DPoint **pt);
void set_y(2DPoint *pt, int newVal);
/*** 2dPoint.c module implementation ***/
#define 2D_POINT_IMPL
#include "2dPoint.h"
#include <stdlib.h>
#include <string.h>
2DPoint *new_2dPoint(void)
{
2DPoint *pt = malloc(sizeof(2DPoint));
pt->x = 42;
pt->y = 666;
return pt;
}
void delete_2dPoint(2DPoint **pt)
{
free(*pt);
*pt = NULL;
}
void set_y(2DPoint *pt, int newVal)
{
pt->y = newVal;
}
#endif /* H_2D_POINT */
/*** main.c user's file ***/
#include "2dPoint.h"
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
2DPoint *pt = new_2dPoint();
pt->x = 10; /* ok */
pt->y = 20; /* Invalid access, y is "private" */
set_y(pt, 30); /* accessor needed */
printf("pt.x = %d, pt.y = %d\n", pt->x, pt->y); /* no accessor needed for reading "private" members */
delete_2dPoint(&pt);
return EXIT_SUCCESS;
}
А теперь вопрос: подходит ли этот трюк для стандарта C? Он отлично работает с GCC, и компилятор ни на что не жалуется, даже с некоторыми строгими флагами, но как я могу быть уверен, что это действительно нормально?
.c
) и предоставляйте методы доступа, либо документируйте, которым поля не должны назначаться. - person Thomas   schedule 26.12.20122DPoint
формирует действительный идентификатор? - person   schedule 26.12.2012