Что такое непрозрачное значение в C ++?

Что такое «непрозрачное значение» в C ++?

Примером для Opaque Value является FILE (из библиотеки C):

 #include  int main() { FILE * fh = fopen( "foo", "r" ); if ( fh != NULL ) { fprintf( fh, "Hello" ); fclose( fh ); } return 0; } 

Вы получаете указатель FILE из fopen() и используете его как параметр для других функций, но вы никогда не беспокоитесь о том, что он на самом деле указывает.

«Непрозрачный» определяется на английском языке как «неспособный быть видимым, непрозрачным». В Computer Science это означает значение, которое не показывает никаких других данных, кроме типа самого значения.

Люди часто используют C-тип FILE в качестве classического примера, но часто это не непрозрачно – детали раскрываются в stdio.h для тех, кто видит, и они просто полагаются на пользователя такого типа, чтобы не возиться с внутренними элементами. Это нормально, если люди придерживаются правил, передавая такие значения таким функциям, как fread() и fclose() но проблема с раскрытием информации заключается в том, что люди иногда (глупо) начинают полагаться на нее.

Например, glibc публикует свою структуру FILE (как struct _IO_FILE ) в libio.h так что тип не является технически непрозрачным.

Обратите внимание, что часть определения на фронте: «не способна», а не «не желает». Непрозрачность требует, чтобы информация скрывалась, а не просто принимала «джентльменское соглашение», чтобы не использовать ее.

Непрозрачные указатели, сделанные правильно, не должны раскрывать никакой информации, кроме самого имени типа, и вы можете реализовать это на С относительно легко. Рассмотрим следующий заголовочный файл 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  #include  #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 

как и следовало ожидать от основной функции.

Это похоже на непрозрачный указатель – значение, которое не хранит данные, которые ваш код может интерпретировать или предоставлять доступ к данным, но только идентифицирует некоторые другие данные. Типичным примером является дескриптор Win32, такой как HBITMAP bitmap handle – вы можете передавать его только соответствующим функциям, но вы не можете ничего сделать с базовым растровым изображением напрямую.

FILE * – хороший пример непрозрачного значения. Вы не используете его напрямую; это единственный «blob», который вы не можете интерпретировать или манипулировать. Вместо этого вы используете набор функций (fopen, fwrite, fprintf и т. Д.), Которые умеют манипулировать им.

Быть непрозрачным таким образом является общим для многих ситуаций (и во многих API), где у вас есть «волшебная» ручка: черный ящик.

из Википедии

В информатике непрозрачный тип данных является типом данных, который не полностью определен в интерфейсе, поэтому его значения могут обрабатываться только путем вызова подпрограмм, имеющих доступ к отсутствующей информации. Конкретное представление типа скрыто от его пользователей

Типичными примерами непрозрачных типов данных являются ручки для ресурсов, предоставляемых операционной системой прикладному программному обеспечению.

Некоторые языки, такие как C, позволяют объявлять непрозрачные записи (структуры), размер и поля которых скрыты от клиента. Единственное, что клиент может сделать с объектом такого типа, это взять его адрес памяти, чтобы создать непрозрачный указатель.

Если информация, предоставленная интерфейсом, достаточна для определения размера этого типа, клиенты могут объявлять переменные, поля и массивы этого типа, присваивать их значения и, возможно, сравнивать их для равенства. Обычно это относится к непрозрачным указателям.

  • Вычислить наибольший прямоугольник во вращающемся прямоугольнике
  • Изучение теории сбора мусора
  • Алгоритм естественной сортировки
  • Как работает переопределение переменных XOR?
  • Что такое оптимизация хвостового звонка?
  • Как найти пару с k-й наибольшей суммой?
  • Что такое lambda?
  • Алгоритм генерации анаграмм
  • Является ли двойным действительно неподходящим для денег?
  • Что такое самоуверенное программное обеспечение?
  • Линия пересечения двух плоскостей
  • Давайте будем гением компьютера.