OpenGLを使用して円を描く関数がありますが、x座標とy座標、および半径を含む構造体を渡したいと思います。問題は、この同じ関数を3つの異なる構造で使用する必要があることです。これらの構造にはすべて、座標、半径、および描画関数が使用しないその他の要素が含まれています。
3つの異なる構造に対して1つの引数のみを持つ方法はありますか(一度に1つだけが送信されます)。
私は十分に正確であったことを望みます。
PS:関数は「抽象的」でなければなりません。
はい、次のようなプロトタイプを使用できます。
void foo(char type, void *data);
タイプを使用して、データを使用する構造体を関数に指示します。これで問題ありません。
struct c *prepareStructC(void);
//...
struct c *toto = prepareStructC();
foo('c', toto);
//...
void foo(char type, void *data)
{
int x, y;
switch (type)
{
case 'c':
x = ((struct c*)data)->x;
y = ((struct c*)data)->y;
break;
//...
}
//...
}
2番目のオプションは、スイッチ/ケースを避け、後でfooを進化させずに構造体タイプを追加できるようにする場合、すべての構造体が必要なデータで始まり、常に同じ順序で、同じタイプであることを確認できます。 。このようにして、C ++から「インターフェイス」のようなものを作成し、次のタイプの抽象バージョンを使用できます。
struct abstract
{
int x;
int y;
int radius;
}
struct a
{
struct abstract abs;
//... other data ...
}
struct b
{
struct abstract abs;
//... other data ...
}
struct c
{
struct abstract abs;
//... other data ...
}
//Two choices : either you have:
void foo(void *data)
{
int x,y,r;
x = ((struct abstract*)data)->x;
y = ((struct abstract*)data)->y;
r = ((struct abstract*)data)->radius;
//...
}
//OR Smarter way:
void foo2(struct abstract *data)
{
int x,y,r;
x = data->x;
y = data->y;
r = data->radius;
}
//Calling foo2 with:
struct a *sa = prepareStructA();
struct b *sb = prepareStructB();
struct c *sc = prepareStructC();
foo2(sa->abs);
foo2(sb->abs);
foo2(sc->abs);
2番目のメソッドの2番目の部分では、柔軟性が高まり、サブタイプ内の特定の情報を分類できます。abs
また、構造体a / b / c内の任意の場所にパーツを配置でき、構造体の単一の目的の原則に優れています(構造体内に座標や半径などを含めることが常に最適であるとは限りません。)
関数が引数としてaを受け入れる場合にのみ、関数内のデータにアクセスするために関数を逆参照する前に、関数内の正しいポインター型にvoid*
をキャストします。void*
typedef enum
{
type1, type2, type3
} datatype;
void foo(void* data, datatype type)
{
switch(type)
{
case type1:
// do something with data by casting it to the proper type
break;
// ... other cases here
}
}
ただし、そうすることvoid*
で、a)渡される前にキャストされる元の型を示す別の引数を渡す必要があり、b)型システムを放棄することになります。これは、ほとんど良い考えではなく、常に避ける必要があります。
このアプローチを採用する場合は、関数(をとる)を内部で呼び出す前に、正しい型をとる3つの「ラッパー」関数を作成することを強くお勧めします。関数を直接呼び出さないことvoid*
を厳密な規則にします。void*
ラッパーを呼び出すだけです。このようにして、コンパイルエラーを支援する型システムがまだあります。
void bar1(someStruct* data)
{
foo((void*) data, type1);
}
void bar2(someOtherStruct* data)
{
foo((void*) data, type2);
}
void bar3(yetAnotherStruct* data)
{
foo((void*) data, type3);
}