简体   繁体   English

在C中模拟访问说明符

[英]Emulate access specifiers in C

Is it possible to emulate C++ access specifiers [public, private, protected] in C ? 是否可以在C中模拟C ++访问说明符[public,private,protected]? More generally, how does the C++ compiler ensure that private members of a class are not accessed by non-member functions ? 更一般地说,C ++编译器如何确保非成员函数不能访问类的私有成员?

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. C ++访问控制完全是编译器想象的一个例子:你不能只访问私有成员,因为编译器会拒绝编译任何试图这样做的代码。

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. 通过欺骗编译器认为指向ClassWithPrivateMember实例的指针实际上是指向ClassWithPublicMember实例的ClassWithPublicMember - 即通过使用略微修改的头文件,您可以访问C ++类的私有成员实际上非常简单通常可以访问您不应该访问的内容。 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. 在C中进行访问控制的最佳方法是将指针传递给opaque类型: struct对象,其定义不适用于客户端代码。 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. 如果你提供一个foo* create_foo()方法和一系列的操作方法foo* ,隐藏的实际定义foo从客户端,那么你就必须取得类似的效果。

// 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 . 现在,您将foo.cfoo.h一起分发到库中。 The functions declared in foo.h form the public interface of a type, but the internal structure of that type is opaque; foo.h声明的函数形成一个类型的公共接口,但该类型的内部结构是不透明的; in effect, the clients who call create_foo() can't access the private members of the foo object. 实际上,调用create_foo()的客户端无法访问foo对象的私有成员。

Our friend the FILE* is a similar sort of thing, except that the type FILE isn't usually truly opaque. 我们的朋友FILE*是类似的东西,除了FILE类型通常不是真正不透明的。 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. 我建议强烈反对使用另一个答案中建议的void *指针,这会抛弃所有类型安全。 You can instead forward-declare struct foo; 你可以改为向前声明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. struct实现隐藏在该单元的.c文件中。

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. 如果要保留在结构和其他类型(例如int)之间进行更改的选项,可以在标头中使用typedef来包装接口的类型。

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. 您可以使用的其他技术包括在.c文件static内声明函数,以便它们不能与其他源链接,即使这些其他源声明了该函数。

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" 该示例包括类“struct test_t”和类函数“test_create”以及成员函数“print”

test.h: 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: 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: main.c中:

#include "test.h"

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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