少し注意すれば、Cで一種のオブジェクト指向プログラミングを実装できます。私が行った方法では、関数ポインターと、関数ポインターをメンバーとして持つ構造体を使用しました。
たとえば、ある種のデータに依存しないようにするために、クイックソート(qsort)関数のように、データを操作する関数へのポインターを備えた長いデータが提供される関数がある場合があります。通常、このアプローチでは、さまざまな種類のvoidポインターを使用して、任意のデータ型へのポインターを使用できるようにします。
私が使用した別のアプローチは、さまざまなタイプのデバイスがサポートする一般的な操作の抽象的なインターフェイスに相当するものを用意し、それらの操作の関数ポインターテンプレートを提供する構造体を作成することです。次に、これらの構造体の配列を作成し、特定のデバイスに対してその操作を実装する特定の関数への関数ポインターを使用して、配列要素を入力します。
たとえば、この非常に単純な例のようなものは、いくつかの異なるデバイスに標準インターフェイスを提供するために使用したものです。このインターフェイスは、標準のインターフェイスを提供することにより、デバイスの違いを隠します。
// I create a struct that specifies what the function
// interface looks like for each of these operations for the
// devices that we are supporting.
typedef struct {
int (*pInput)(int iValue);
char *(*pName) (void);
int (*pDance) (int iTune, char *aszName);
} HardwareInterface;
// next I provide the function prototypes for the various devices.
// we have two different devices, Device_01 and Device_02 which
// have a common set of operations with the same interface.
int Device_01_Input (int iValue);
char *Device_01_Name (void);
int Device_01_Dance (int iTune, char *aszName);
int Device_02_Input (int iValue);
char *Device_02_Name (void);
int Device_02_Dance (int iTune, char *aszName);
// now I define my array of the device operation interfaces.
// this is where I provide the link between a specific operation
// on a specific device. I will number my devices beginning with
// zero to the number of devices supported minus one.
HardwareInterface HardwareList [] = {
{Device_01_Input, Device_01_Name, Device_01_Dance},
{Device_02_Input, Device_02_Name, Device_02_Dance},
};
この時点で、実際に使用したいデバイスを取得するために呼び出す関数を使用できます。この関数は、ハードウェアリストにインデックスを返します。だから、こんな感じになるかもしれません。
int DeviceStdInput (int iValue)
{
int i = GetDeviceType ();
return HardwareList[i].pInput (iValue);
}
または、ハンドルアプローチを使用して、関数に渡される説明で指定されているデバイスにハンドルを提供する関数を呼び出すこともできます。次に、標準インターフェースを呼び出すとハンドルが指定されます。その下にあるハンドルは、さまざまなデバイスの配列への単なるインデックスです。
{
int iHandle = GetDeviceHandle ("Device_01");
int iXvalue = DeviceStdInput (iHandle, iValue);
}
そして、関数DeviceStdInput()は次のようになります。
int DeviceStdInput (int iHandle, int iValue)
{
return HardwareList[iHandle].pInput (iValue);
}
各デバイスに使用される実際の関数を実装する必要がありますが、これにより、コードの残りの部分で標準インターフェイスを使用できる共通の操作を備えた複数のデバイスへの標準インターフェイスを使用できます。
これを使用して、出力デバイスがファイル、プリンター、およびWebサービスである出力用の標準インターフェースを提供しました。実際のシンクまたは出力デバイスは、ユーザーが選択しました。インターフェイスを使用するコードは変更されませんでした。インターフェイスが変更されない限り、デバイスの追加は非常に簡単でした。場合によっては、特定の操作をサポートしていないデバイスがあり、その機能は何もせずに戻るだけでした。