«Непрозрачный» на английском языке определяется как «невидимый, непрозрачный». В области компьютерных наук это означает значение, которое не раскрывает никаких деталей, кроме типа самого значения.
Люди часто используют тип C FILE
в качестве классического примера, но часто это , а не непрозрачно - подробности раскрываются в stdio.h
, чтобы все могли их видеть, и они просто полагаются на пользователя типа, чтобы не возиться с внутренностями. Это нормально, если люди придерживаются правил, передавая такие значения только таким функциям, как fread()
и fclose()
, но проблема с раскрытием информации заключается в том, что люди иногда (по глупости) начинают полагаться на нее.
Например, glibc
публикует свою структуру FILE
(как struct _IO_FILE
) в libio.h
, так что тип не является технически непрозрачным.
Обратите внимание, что часть определения на фронте: "не способен" вместо "не хочет". Непрозрачность требует, чтобы информация была скрыта, а не просто введена в действие "джентльменом" соглашение "не использовать его.
Непрозрачные указатели, выполненные правильно, должны показывать no информацию, отличную от самого имени типа, и вы можете реализовать это в C относительно легко. Рассмотрим следующий заголовочный файл prog2.h
для получения и освобождения xyzzy
объектов:
struct xyzzy;
struct xyzzy *xyzzyOpen (void);
void xyzzyClose (struct xyzzy *fh);
Это все, что видят клиенты кода, неполный тип struct xyzzy
и некоторые функции для выделения и освобождения объектов этого типа (они не видят prog2.c
, подробно описанную ниже). Обратите внимание, что указатели на неполный тип хороши, но вы не можете создать экземпляр объекта этого типа, так как вы не знаете его внутренности. Итак, код:
struct xyzzy myvar;
вызовет ошибку в следующем виде:
prog1.c: In function ‘main’:
prog1.c:3:15: error: storage size of 'myvar' isn't known
Теперь вы можете с радостью использовать эти функции из программы prog1.c
без , зная внутренние структуры:
#include "prog2.h"
int main (void) {
//struct xyzzy myvar; // will error
struct xyzzy *num1 = xyzzyOpen();
struct xyzzy *num2 = xyzzyOpen();
struct xyzzy *num3 = xyzzyOpen();
xyzzyClose (num1);
xyzzyClose (num3); // these two intentionally
xyzzyClose (num2); // reversed.
return 0;
}
И реализация вызовов, prog2.c
, фактически контролирует и знает внутренних устройств, поэтому может использовать их довольно свободно:
#include <stdio.h>
#include <stdlib.h>
#include "prog2.h"
struct xyzzy { int payload; };
static int payloadVal = 42;
struct xyzzy *xyzzyOpen (void) {
struct xyzzy *plugh = malloc (sizeof (struct xyzzy));
plugh->payload = payloadVal++;
printf ("xyzzyOpen payload = %d\n", plugh->payload);
return plugh;
}
void xyzzyClose (struct xyzzy *plugh) {
printf ("xyzzyClose payload = %d\n", plugh->payload);
free (plugh);
}
Вызовы printf
предназначены просто для того, чтобы показать, что он может использовать внутренние компоненты, и вы, вероятно, захотите добавить проверку возвращаемого значения из malloc
в готовом к использованию коде, но это не относится к цели этот пример.
Когда вы компилируете prog1.c
и prog2.c
в один исполняемый файл и запускаете его, вывод:
xyzzyOpen payload = 42
xyzzyOpen payload = 43
xyzzyOpen payload = 44
xyzzyClose payload = 42
xyzzyClose payload = 44
xyzzyClose payload = 43
как и следовало ожидать от основной функции.