C で C++ アクセス指定子 [public, private, protected] をエミュレートすることは可能ですか? より一般的には、C++ コンパイラは、クラスのプライベート メンバーが非メンバー関数によってアクセスされないようにするにはどうすればよいでしょうか?
3 に答える
C++ のアクセス制御は、完全にコンパイラの想像力の産物です。プライベート メンバーにアクセスできないのは、コンパイラがそうしようとするコードのコンパイルを拒否するためだけです。
ClassWithPrivateMember
のインスタンスへのポインターが実際にはのインスタンスへのポインターであるとコンパイラーに認識させることにより、C++ クラスのプライベート メンバーにアクセスするのは実際にはかなり簡単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」が含まれています。
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);
}