OOP をエミュレートする C で頻繁に現れるパターンを次に示します。
MyClass という名前のクラスを考えてみましょう。
/* MyClass.h or myclass.h */
#ifndef MYCLASS_H
#define MYCLASS_H
struct myclass_s;
typedef struct myclass_s myclass_t;
myclass_t * myclass_new();
void delete_myclass(myclass_t *);
// Method int doMyStuff(int arg1,int arg2)
int myclass_doMyStuff(myclass_t *, int arg1, int arg2);
#endif //MYCLASS_H
ヘッダー ファイルはタイプ myclass_t を定義しますが、実際の実装 myclass_s を隠します。この 2 つの名前を持つというやや厄介な要件は、C では構造体が別の名前空間にあるのに対し、C++ では構造体は他のすべての型と同じ名前空間にあります。このコードは、C と C++ の両方で動作するように意図されています。対応する .c ファイルは次のとおりです。
/* MyClass.c or myclass.c */
#include "myclass.h" // Or MyClass.h
struct myclass_s {
int exampleField;
};
myclass_t * myclass_new()
{
myclass_t * o=(myclass_t*)malloc(sizeof(myclass_t));
// Initialize o here.
return o;
}
void myclass_delete(myclass_t * o)
{
// Do any cleanup needed on o here.
free(o);
}
int myclass_doMyStuff(myclass_t * o,int arg1,int arg2)
{
// ...
}
継承と動的バインディングも C で行うことができますが、多少複雑になります。上記のパターン、または OOP をモデル化するパターンは、C で物事を行うための最良の方法であるとは限らないため、クラス中心の考え方にとらわれないようにしてください。それでも、このパターンが役立つ場合があります。たとえば、libpng はこれに近いものを使用します (彼らは setjmp/longjmp を使用して「例外」も行いますが、これは私が推奨するものではありません)。