是否可以在 C 中模拟 C++ 访问说明符 [public、private、protected]?更一般地说,C++ 编译器如何确保类的私有成员不被非成员函数访问?
3 回答
C++ 访问控制完全是编译器的想象:你不能访问私有成员,因为编译器会拒绝编译任何试图这样做的代码。
访问 C++ 类的私有成员实际上相当简单,方法是诱使编译器认为指向 的实例的ClassWithPrivateMember
指针实际上是指向ClassWithPublicMember
访问你不应该访问的东西。不是说有人做过这样的事……
在 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.c
编译后的文件与foo.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 = %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;
}
主.c:
#include "test.h"
int main()
{
struct test_t *test = test_create(10);
test->print(test);
}