模拟 C 中的访问说明符

Emulate access specifiers in C

本文关键字:访问 说明符 模拟      更新时间:2023-10-16

是否可以在 C 语言中模拟C++访问说明符 [public, private, protected] ?更一般地说,C++编译器如何确保非成员函数不会访问类的私有成员?

C++访问控制完全是编译器想象的虚构:您不能访问私有成员,因为编译器会拒绝编译任何尝试这样做的代码。

实际上,通过欺骗编译器认为指向ClassWithPrivateMember实例的指针实际上是指向ClassWithPublicMember实例的指针来访问C++类的私有成员实际上相当简单 - 即,通过使用稍微修改的头文件,您通常可以访问不应该访问的内容。并不是说有人做过这样的事情...

在 C 语言中执行访问控制的最佳方法是传递指向不透明类型的指针:struct对象,其定义不适用于客户端代码。如果您提供一个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;
}

现在,您将编译foo.cfoo.h一起分发到库中。foo.h声明的函数构成类型的公共接口,但该类型的内部结构是不透明的;实际上,调用 create_foo() 的客户端无法访问 foo 对象的私有成员。

我们的朋友FILE*也是类似的东西,只是FILE类型通常不是真正不透明的。只是大多数人(明智地)不会戳穿它的内脏。在那里,访问控制仅通过默默无闻来实施。

我强烈建议不要按照另一个答案(自修复以来)的建议使用 void* 指针,这会丢弃所有类型安全。您可以在标头中向前声明struct foo;而不指定内容,然后可以将这些结构和指针传入和传出标头中声明的接口函数。结构实现隐藏在该单元的 .c 文件中。

如果你想保留在结构体和其他类型的类型(例如 int)之间切换的选项,你可以在标头中使用typedef来包装接口的类型。

可以使用的其他技术包括在该 .c 文件static内声明函数,以便它们无法从其他源链接,即使这些其他源声明了该函数也是如此。

有很多方法可以实现目标,以下是我的:

该示例包括一个类"struct test_t"和一个类函数"test_create"和一个成员函数"print"

测试.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);

测试.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 = %dn", 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;
}

主.c:

#include "test.h"
int main()
{
    struct test_t *test = test_create(10);
    test->print(test);
}