c でプライベート変数が必要な場合は、プライベート変数を近似できる手法がいくつかありますが、C 言語には、(C++ のように) プライベート、パブリック、プロテクトに拡張される「保護」の概念が実際にはありません。
C は任意の変数の名前を表示します (これは C の要件です)。そのため、変数の型を隠す情報 (逆参照を非常に困難にする)のアイデアを使用してアプローチする必要があります。
1 つのトリックは、変数を として定義void*
し、実際の変数の型が 1 つの.c
モジュールでのみ認識されるようにすることです。
/* somefile.h */
extern void* counter;
/* somefile.c */
#include "somefile.h"
int actualCounter = 0;
void* counter = &actualCounter;
/* otherfile.c */
#include "somefile.h"
// we can see "counter", but we cannot "use" it here; because we don't have access
// to the real "hidden" type of "int".
より良い方法は、struct
キーワードを使用してこのアイデアを拡張し、次のように疑似メソッドを作成することです。
/* person.h */
struct s_person;
typedef Person struct s_person;
Person* new_Person(char* name);
void delete_Person(Person* person);
void Person_setName(Person* person, char* name);
char* Person_getName(Person* person);
/* person.c */
struct s_person {
char* name;
};
Person* new_Person(char* name) {
Person* object = (Person*)malloc(sizeof(struct s_person));
// duplicate the string for more security, otherwise constructor
// could manipulate the "private" string after construction.
object->name = strdup(name);
return object;
}
void delete_Person(Person* person) {
// some implementations pass a Person** to set the reference to 0
// this implementation requires that the caller sets his own references to 0
free(person->name);
free(person);
}
void Person_setName(Person* person, char* name) {
// free the old
free(person->name);
// duplicate the new to provide "out of simulated class" modification by malicious
// name setter.
person->name = strdup(name);
}
char* Person_getName(Person* person) {
// must return a copy, otherwise one can manipulate name
// from reference provided by Person_getName(...);
return strdup(person->name);
}
/* otherfile.c */
#include "Person.h"
/* Now we can hold Person "simulated objects", but we cannot */
/* manipulate their "state" without using the C simulated object */
/* methods */
int main(int argc, char** argv) {
Person* bob = new_Person("bob");
printf("%s\n", Person_getName(bob));
delete_Person(bob);
// critical or we hold a pointer to freed memory.
bob = 0;
return 0;
}
このような手法にはいくつかのバリエーションがあります。1 つは、「プライベート構造体」への void* ポインターを持つ「パブリック構造体」を持つことです。1 つは「メソッド」を「public struct」に関数ポインタとして含めること (ポリモーフィズムをサポートするためのステップ) です。もう 1 つは、C++ とまったく同じように物事を解決しようとする完全かつ適切な C++ 型システムを実際に記述することです (クラス階層、ポリモーフィズム、レイト バインディング、情報隠蔽など)。
基本的に、あまり手間をかけずに「オブジェクト指向性」を得ることができますが、装飾の機能を追加すると、グルー コードが追加されます (オブジェクト指向プログラミング言語を実際に使用する方がはるかに簡単になるまで)。 .