In C++ and Java, data structures can have private
, public
and protected
regions. I'd like to port this concept to a C language program I am writing.
Are there any idioms for implementing private or protected function pointers and data fields in a C struct
?
I know that C struct
s are public, I'm looking for an idiom to help hide some implementation details and force users to use the public interface.
Note: The language has been chosen by the shop, so I am stuck implementing Object Oriented concepts into C.
Thanks.
As you know, you cannot do this. However, there are idioms that will allow a similar effect.
C will allow you do do something similar to what is known as the "pimpl" idiom in object-oriented design. Your struct can have an opaque pointer to another forward-declared struct that acts as the struct's private data. Functions that operate on the struct, taking the place of member functions, can have the full definition for the private member, and can make use of it, while other parts of the code cannot. For example:
In a header, foo.h:
struct FooPrivate;
struct Foo {
/* public: */
int x;
double y;
/* private: */
struct FooPrivate* p;
};
extern struct Foo* Foo_Create(); /* "constructor" */
extern void Foo_DoWhatever(struct Foo* foo); /* "member function" */
In the implementation, foo.c:
struct FooPrivate {
int z;
};
struct Foo* Foo_Create()
{
struct Foo* foo = malloc(sizeof(Foo));
foo->p = malloc(sizeof(FooPrivate));
foo->x = 0;
foo->y = 0;
foo->p->z = 0;
return foo;
}
void Foo_DoWhatever(struct Foo* foo)
{
foo->p->z = 4; /* Can access "private" parts of foo */
}
In a program:
#include "foo.h"
int main()
{
struct Foo* foo = Foo_Create();
foo->x = 100; /* Can access "public" parts of foo */
foo->p->z = 20; /* Error! FooPrivate is not fully declared here! */
Foo_DoWhatever(foo); /* Can call "member" function */
return 0;
}
Note the need to use a "constructor" function in order to allocate memory for the private data. Obviously you would need to pair this with a special "destructor" function in order to deallocate the private data properly.
Or, alternatively, if you would like your struct to have no public fields whatsoever, you could make the entire struct opaque, and just have the header be something like
struct Foo;
extern struct Foo* Foo_Create(); /* "constructor" */
extern void Foo_DoWhatever(struct Foo* foo); /* "member function" */
With the actual definition of struct Foo
in foo.c, and getter and setter functions available for any properties you would like to provide direct access to.