简体   繁体   中英

Emulate access specifiers in C

Is it possible to emulate C++ access specifiers [public, private, protected] in C ? More generally, how does the C++ compiler ensure that private members of a class are not accessed by non-member functions ?

C++ access control is entirely a figment of the compiler's imagination: you can't access a private member only because the compiler will refuse to compile any code that tries to do so.

It's actually fairly simple to access a private member of a C++ class by tricking the compiler into thinking that a pointer to an instance of ClassWithPrivateMember is actually a pointer to an instance of ClassWithPublicMember -- ie, by using a slightly modified header file, you can generally get access to things you shouldn't. Not that anyone ever does anything like that...

The best way to do access control in C is by passing around pointers to an opaque type: struct objects the definition of which is not available to client code. If you provide a foo* create_foo() method and a series of methods that operate on foo* , hiding the actual definition of foo from the client, then you'll have achieved a similar effect.

// File "foo_private.h"
struct foo {
    int private1;
    char private2;
};

// File "foo.h"
typedef struct foo foo;
foo * create_foo(int x, char y);
int mangle_foo(foo *);

// file "foo.c"
#include <stdlib.h>
#include "foo.h"
#include "foo_private.h"

foo * create_foo(int x, char y) {
    foo * f = (foo *) calloc(1, sizeof(foo));
    f->private1 = x;
    f->private2 = y;
}    

int mangle_foo(foo *f) {
    return f->private1 + f->private2;
}

Now, you distribute foo.c compiled into a library, along with foo.h . The functions declared in foo.h form the public interface of a type, but the internal structure of that type is opaque; in effect, the clients who call create_foo() can't access the private members of the foo object.

Our friend the FILE* is a similar sort of thing, except that the type FILE isn't usually truly opaque. It's just that most people (wisely) don't go poking through its innards. There, access control is enforced merely by obscurity.

I would advise strongly against using void* pointers as suggested in another answer, that throws away all type-safety. You can instead forward-declare struct foo; in a header without specifying the contents, then you can pass those structs and pointers to them in and out of interface functions declared in a header. The struct implementation is hidden inside that unit's .c file.

If you want to keep the option of changing between a struct and other types eg int, you can use typedef in your header to wrap the type for the interface.

Other techniques you can use include declaring functions inside that .c file static so that they cannot be linked from other sources, even if those other sources declare the function.

There are many ways to achieve the goal, followings are mine:

The example includes a class "struct test_t" and a class function "test_create" and a member function "print"

test.h:

struct test_t {
    // Member functions
    void (*print)(struct test_t *thiz);

    // Private attributes
    char priv[0];
};


// Class functions
struct test_t *test_create(int number);

test.c:

#include "test.h"
#include <stdio.h>
#include <stdlib.h>

// priv attr
struct test_priv_t {
    int number;
};


// member functions
static void print(struct test_t *thiz)
{
    struct test_priv_t *priv = (struct test_priv_t*)thiz->priv;
    printf("number = %d\n", priv->number);
}


// Class functions
struct test_t *test_create(int number)
{
    struct test_t *test = (struct test_t *)malloc(sizeof(struct test_t) + sizeof(struct test_priv_t));

    // setup member function
    test->print = print;

    // initialize some priv attr
    struct test_priv_t *priv = (struct test_priv_t*)test->priv;
    priv->number = number;

    return test;
}

main.c:

#include "test.h"

int main()
{
    struct test_t *test = test_create(10);
    test->print(test);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM