Click to See Complete Forum and Search --> : Hiding private members from users
rentzk
April 13th, 1999, 04:27 PM
I'm sure this situation has occured to a lot of people, but not to me before. I have a static library that I'm planning on giving to some other people to use. The interface is through an include file that contains a number of interface classes. These classes have as private members a number of structures that are defined in various other include files. I would like to be able to just give the one main .h file to the users along with the library. Doing this results in a number of undefined structures on the users side without all of the other includes. What is the prefered way (assuming there is one) of keeping these variables out of the include file the end user uses? It's not that I need to hide the existence of the structures from anyone, I just don't want to have to give them 10-15 other include files just so they can compile. Not only would this be awkward, but that would be showing a little too much of some of our internal code.
Paul McKenzie
April 13th, 1999, 05:21 PM
How about this:
If your users are not going to use the structures that you want hidden, why not have void pointers instead of the structures? In your internal code, you would cast the void pointer to the appropriate structure type. Your users won't know what it is, and they can't dissasemble it. I would suggest even typedef'ing the void pointer so as to "hint" as to what it really is. "typedef void * INTERNAL1;" or something like (the last point is really for your sake :-())
This should cut down on the dependencies in your header files, since voids will always compile Ok.
However, if your users are going to use the "hidden" structures explicitly, you have no choice but to give them the headers.
Also, is the implementation in the header files themselves? I usually make sure that the implementation is in a separate .CPP file and not in the header file (on the other hand, you may be using templates).
Regards,
Paul McKenzie
Gomez Addams
April 13th, 1999, 05:25 PM
I am in a situtation that is identical to yours. If you use pointers to the 'other'
data items it is very easy. If you use actual instances of them it is a bit
more difficult. What I do is I have a private directory (incprv) that is
never distributed and one that is public (inc). The other thing I do is I use
header files that look something like this :
#ifndef _LIBSOURCE_CPP // defined in source before including this file
typedef void * TypePtr;
#endif
class DllClass MyClass
{
TypePtr m_Type;
};
As I said, since I use pointers this is very easy.
If you are not using pointers then one option is to determine the size of
the various structures and make character arrays of identical size. You
can determine this by making a little test program that just prints out the
size of a batch of data structures. I did this just for my own information.
Here a little program that can do this for you (It will actually compile and run) :
typedef struct // data structure info
{
char * strname;
size_t strsize;
} StrInfo;
// a macro that loads one structure entry into an array
#define STRENTRY(a) #a,sizeof(a)
StrInfo info[] =
{
{ STRENTRY( FILE ) },
{ STRENTRY( LOGFONT ) },
{ STRENTRY( XFORM ) },
{ STRENTRY( BITMAP ) },
{ NULL, 0 } // terminating entry
};
int main( int ac, char *av[] )
{
int x = 0;
while( info[x].strname != NULL )
{
printf( "structure %s size is %d bytes\n",
info[x].strname, info[x].strsize );
x += 1;
}
return 0;
}
rentzk
April 13th, 1999, 05:41 PM
I'm actually using the void * typecasting at the moment and it works pretty good. I just seem to recall that there was another way that at least looked more elegant. I'm probably just a little void shy due to my last job. The owner/programmer believed in just casting everything to void to make legitimate compile problems go away. He got away with it just enough that he thought he knew what he was doing.
rentzk
April 13th, 1999, 05:43 PM
That's the solution I (almost) remembered. Thanks for jumpstarting my brain.
Paul McKenzie
April 13th, 1999, 10:07 PM
You can have an extra int or long member in the strucuture that serves as a unique signature. When you cast the void to the structure, check if the signature of the structure matches the right signature. The chances that the signature is correct for a bad structure is 1 in 4 billion+ (assuming the signature is unsigned long).
Another approach is to use a "class factory". When the user wants to use a class, they must request one from the factory (they can't call "new" or create instances on the fly, the factory is responsible for returning valid instances to the user). Also, you would use the class factory as a proxy to the classes member functions. The user must pass the class object and whatever other parameters to the desired class factory function. The factory can then check if the object is valid, before calling the actual class function.
Just some ideas...
Regards,
Paul McKenzie
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.