¿Qué es un valor opaco en C ++?

¿Qué es un “valor opaco” en C ++?

Un ejemplo para un valor opaco es FILE (de la biblioteca C):

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

FILE un puntero FILE desde fopen() y lo usas como parámetro para otras funciones, pero nunca te molestas con lo que realmente apunta.

“Opaco” se define, en inglés, como “no se puede ver a través, no es transparente”. En Informática, esto significa un valor que no revela detalles distintos del tipo del valor en sí.

Las personas a menudo usan el tipo C FILE como el ejemplo clásico, pero a menudo esto no es opaco: los detalles se revelan en stdio.h para que todos los vean y simplemente confían en el usuario del tipo para no jugar con las partes internas. Eso está bien siempre y cuando la gente se adhiera a las reglas, solo pasando tales valores a funciones como fread() y fclose() pero el problema con la revelación de información es que las personas algunas veces (neciamente) comienzan a confiar en ello.

Por ejemplo, glibc publica su estructura FILE (como struct _IO_FILE ) en libio.h por lo que ese tipo no es técnicamente opaco.

Tenga en cuenta que parte de la definición en el frente: “no capaz” en lugar de “no dispuesto”. La opacidad requiere que la información esté oculta en lugar de solo promulgar un “acuerdo de caballeros” para no usarla.

Los punteros opacos, hechos correctamente, no deben revelar ninguna información que no sea el nombre del tipo en sí y se puede implementar en C con relativa facilidad. Considere el siguiente archivo de encabezado prog2.h para obtener y liberar objetos xyzzy :

 struct xyzzy; struct xyzzy *xyzzyOpen (void); void xyzzyClose (struct xyzzy *fh); 

Esto es todo lo que ven los clientes del código, un tipo incompleto struct xyzzy y algunas funciones para asignar y liberar objetos de ese tipo (no pueden ver el prog2.c detallado a continuación). Tenga en cuenta que los punteros a un tipo incompleto están bien, pero no puede crear una instancia de un objeto de ese tipo ya que no conoce su interior. Entonces el código:

 struct xyzzy myvar; 

causaría un error en la línea de:

 prog1.c: In function 'main': prog1.c:3:15: error: storage size of 'myvar' isn't known 

Ahora puede usar esas funciones de un progtwig prog1.c sin conocer las funciones internas de la estructura:

 #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; } 

Y la implementación de las llamadas, prog2.c , realmente controla y conoce las prog2.c internas, por lo que puede usarlas con total libertad:

 #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); } 

Las llamadas de printf están allí simplemente para mostrar que puede usar las partes internas, y es probable que desee agregar la verificación del valor de retorno de malloc en el código listo para la producción, pero eso no es relevante para el propósito de este ejemplo.

Cuando comstack prog1.c y prog2.c en un único ejecutable y lo ejecuta, el resultado es:

 xyzzyOpen payload = 42 xyzzyOpen payload = 43 xyzzyOpen payload = 44 xyzzyClose payload = 42 xyzzyClose payload = 44 xyzzyClose payload = 43 

como es de esperar de la función principal.

Es similar al puntero opaco : un valor que no almacena los datos que su código podría interpretar o proporcionar acceso a los datos, pero solo identifica algunos otros datos. Un ejemplo típico es un identificador de Win32 como el HBITMAP bitmap HBITMAP : solo puede pasarlo a funciones relevantes, pero no puede hacer nada directamente con el bitmap subyacente.

ARCHIVO * es un buen ejemplo de un valor opaco. No lo usas directamente; es un solo “blob” que no puedes interpretar o manipular. En su lugar, utiliza un conjunto de funciones (fopen, fwrite, fprintf, etc.) que saben cómo manipularlo.

Ser opaco de esta manera es común en muchas situaciones (y en muchas API) donde tienes un mango “mágico”: una caja negra.

de Wikipedia

En informática, un tipo de datos opaco es un tipo de datos que está definido de forma incompleta en una interfaz, de modo que sus valores solo se pueden manipular llamando a subrutinas que tienen acceso a la información faltante. La representación concreta del tipo está oculta a sus usuarios

Los ejemplos típicos de tipos de datos opacos incluyen identificadores de recursos proporcionados por un sistema operativo al software de aplicación.

Algunos lenguajes, como C, permiten la statement de registros opacos (estructuras), cuyo tamaño y campos están ocultos para el cliente. Lo único que el cliente puede hacer con un objeto de ese tipo es tomar su dirección de memoria para generar un puntero opaco.

Si la información proporcionada por la interfaz es suficiente para determinar el tamaño del tipo, los clientes pueden declarar variables, campos y matrices de ese tipo, asignar sus valores y posiblemente compararlos para la igualdad. Este suele ser el caso para punteros opacos.