What is an "opaque value" in C++?
In computer programming, an opaque pointer is a special case of an opaque data type, a data type declared to be a pointer to a record or data structure of some unspecified type. Opaque pointers are present in several programming languages including Ada, C, C++, D and Modula-2.
Opaque pointer is a pointer which points to a data structure whose contents are not exposed at the time of its definition.
An opaque data type is a user-defined or built-in data type that is fully encapsulated. The internal structure of an opaque data type is unknown to the database server. Except for user-defined types (UDTs) that are DISTINCT of built-in non-opaque types, UDTs whose source types are built-in types are opaque data types.
An opaque object and its handle are significant only at the process where the object was created, and cannot be transferred to another process. MPI provides certain predefined opaque objects and predefined, static handles to these objects. Such objects may not be destroyed.
"Opaque" is defined, in English, as "not able to be seen through; not transparent". In Computer Science, this means a value which reveals no details other then the type of the value itself.
People often use the C type FILE
as the classic example but often this is not opaque - the details are revealed in stdio.h
for anyone to see and they simply rely on the user of the type to not fiddle with the internals. That's fine as long as people stick to the rules, only passing such values to functions like fread()
and fclose()
but the problem with revealing information is that people sometimes (foolishly) begin to rely on it.
For example, glibc
publishes its FILE
structure (as struct _IO_FILE
) in libio.h
so that type is not technically opaque.
Note that part of the definition at the front: "not able" rather than "not willing". Opacity requires the information to be hidden rather than just enacting a "gentleman's agreement" not to use it.
Opaque pointers, done correctly, should reveal no information other than the type name itself and you can implement that in C relatively easily. Consider the following header file prog2.h
for obtaining and releasing xyzzy
objects:
struct xyzzy; struct xyzzy *xyzzyOpen (void); void xyzzyClose (struct xyzzy *fh);
This is all that clients of the code see, an incomplete type struct xyzzy
and some functions to allocate and release objects of that type (they don't get to see prog2.c
detailed below). Note that pointers to an incomplete type are fine but you cannot instantiate an object of that type since you don't know its internals. So the code:
struct xyzzy myvar;
would cause an error along the lines of:
prog1.c: In function ‘main’: prog1.c:3:15: error: storage size of 'myvar' isn't known
Now you can quite happily use those functions from a program prog1.c
without knowing the internals of the structure:
#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; }
And the implementation of the calls, prog2.c
, actually controls and knows the internals, so can use them quite freely:
#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); }
The printf
calls are there simply to show that it can use the internals, and you'd probably want to add checking of the return value from malloc
in production-ready code but that's not relevant to the purpose of this example.
When you compile prog1.c
and prog2.c
into a single executable and run it, the output is:
xyzzyOpen payload = 42 xyzzyOpen payload = 43 xyzzyOpen payload = 44 xyzzyClose payload = 42 xyzzyClose payload = 44 xyzzyClose payload = 43
as you would expect from the main function.
An example for an Opaque Value is FILE
(from the C library):
#include <stdio.h> int main() { FILE * fh = fopen( "foo", "r" ); if ( fh != NULL ) { fprintf( fh, "Hello" ); fclose( fh ); } return 0; }
You get a FILE
pointer from fopen()
, and use it as a parameter for other functions, but you never bother with what it actually points to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With