これは、必要な正確な「オブジェクト指向」機能セットによって異なります。オーバーロードや仮想メソッドなどが必要な場合は、おそらく構造体に関数ポインタを含める必要があります。
typedef struct {
float (*computeArea)(const ShapeClass *shape);
} ShapeClass;
float shape_computeArea(const ShapeClass *shape)
{
return shape->computeArea(shape);
}
これにより、基本クラスを「継承」し、適切な関数を実装することで、クラスを実装できます。
typedef struct {
ShapeClass shape;
float width, height;
} RectangleClass;
static float rectangle_computeArea(const ShapeClass *shape)
{
const RectangleClass *rect = (const RectangleClass *) shape;
return rect->width * rect->height;
}
もちろん、これにはコンストラクタも実装する必要があります。これにより、関数ポインタが適切に設定されます。通常、インスタンスにメモリを動的に割り当てますが、呼び出し側にもそれを行わせることができます。
void rectangle_new(RectangleClass *rect)
{
rect->width = rect->height = 0.f;
rect->shape.computeArea = rectangle_computeArea;
}
複数の異なるコンストラクタが必要な場合は、関数名を「装飾」する必要があります。複数の関数を含めることはできませんrectangle_new()
。
void rectangle_new_with_lengths(RectangleClass *rect, float width, float height)
{
rectangle_new(rect);
rect->width = width;
rect->height = height;
}
使用法を示す基本的な例を次に示します。
int main(void)
{
RectangleClass r1;
rectangle_new_with_lengths(&r1, 4.f, 5.f);
printf("rectangle r1's area is %f units square\n", shape_computeArea(&r1));
return 0;
}
これで少なくともいくつかのアイデアが得られるといいのですが。Cで成功したリッチなオブジェクト指向フレームワークについては、glibのGObjectライブラリを調べてください。
上記でモデル化されている明示的な「クラス」がないことにも注意してください。各オブジェクトには独自のメソッドポインターがあり、C ++で通常見られるよりも少し柔軟です。また、メモリも消費します。メソッドポインタをclass
構造体に詰め込むことでそれを回避し、各オブジェクトインスタンスがクラスを参照する方法を発明できます。